Overview

1. Native type in C++, wrapper in Python

Exposing a custom C++ type using py::class_ was covered in detail in the Object-oriented code section. There, the underlying data structure is always the original C++ class while the py::class_ wrapper provides a Python interface. Internally, when an object like this is sent from C++ to Python, pybind11 will just add the outer wrapper layer over the native C++ object. Getting it back from Python is just a matter of peeling off the wrapper.

2. Wrapper in C++, native type in Python

This is the exact opposite situation. Now, we have a type which is native to Python, like a tuple or a list. One way to get this data into C++ is with the py::object family of wrappers. These are explained in more detail in the Python types section. We’ll just give a quick example here:

void print_list(py::list my_list) {
    for (auto item : my_list)
        std::cout << item << " ";
}
>>> print_list([1, 2, 3])
1 2 3

The Python list is not converted in any way – it’s just wrapped in a C++ py::list class. At its core it’s still a Python object. Copying a py::list will do the usual reference-counting like in Python. Returning the object to Python will just remove the thin wrapper.

3. Converting between native C++ and Python types

In the previous two cases we had a native type in one language and a wrapper in the other. Now, we have native types on both sides and we convert between them.

void print_vector(const std::vector<int> &v) {
    for (auto item : v)
        std::cout << item << "\n";
}
>>> print_vector([1, 2, 3])
1 2 3

In this case, pybind11 will construct a new std::vector<int> and copy each element from the Python list. The newly constructed object will be passed to print_vector. The same thing happens in the other direction: a new list is made to match the value returned from C++.

Lots of these conversions are supported out of the box, as shown in the table below. They are very convenient, but keep in mind that these conversions are fundamentally based on copying data. This is perfectly fine for small immutable types but it may become quite expensive for large data structures. This can be avoided by overriding the automatic conversion with a custom wrapper (i.e. the above-mentioned approach 1). This requires some manual effort and more details are available in the Making opaque types section.

List of all builtin conversions

The following basic data types are supported out of the box (some may require an additional extension header to be included). To pass other data structures as arguments and return values, refer to the section on binding Object-oriented code.

Data type

Description

Header file

int8_t, uint8_t

8-bit integers

pybind11/pybind11.h

int16_t, uint16_t

16-bit integers

pybind11/pybind11.h

int32_t, uint32_t

32-bit integers

pybind11/pybind11.h

int64_t, uint64_t

64-bit integers

pybind11/pybind11.h

ssize_t, size_t

Platform-dependent size

pybind11/pybind11.h

float, double

Floating point types

pybind11/pybind11.h

bool

Two-state Boolean type

pybind11/pybind11.h

char

Character literal

pybind11/pybind11.h

char16_t

UTF-16 character literal

pybind11/pybind11.h

char32_t

UTF-32 character literal

pybind11/pybind11.h

wchar_t

Wide character literal

pybind11/pybind11.h

const char *

UTF-8 string literal

pybind11/pybind11.h

const char16_t *

UTF-16 string literal

pybind11/pybind11.h

const char32_t *

UTF-32 string literal

pybind11/pybind11.h

const wchar_t *

Wide string literal

pybind11/pybind11.h

std::string

STL dynamic UTF-8 string

pybind11/pybind11.h

std::u16string

STL dynamic UTF-16 string

pybind11/pybind11.h

std::u32string

STL dynamic UTF-32 string

pybind11/pybind11.h

std::wstring

STL dynamic wide string

pybind11/pybind11.h

std::string_view, std::u16string_view, etc.

STL C++17 string views

pybind11/pybind11.h

std::pair<T1, T2>

Pair of two custom types

pybind11/pybind11.h

std::tuple<...>

Arbitrary tuple of types

pybind11/pybind11.h

std::reference_wrapper<...>

Reference type wrapper

pybind11/pybind11.h

std::complex<T>

Complex numbers

pybind11/complex.h

std::array<T, Size>

STL static array

pybind11/stl.h

std::vector<T>

STL dynamic array

pybind11/stl.h

std::deque<T>

STL double-ended queue

pybind11/stl.h

std::valarray<T>

STL value array

pybind11/stl.h

std::list<T>

STL linked list

pybind11/stl.h

std::map<T1, T2>

STL ordered map

pybind11/stl.h

std::unordered_map<T1, T2>

STL unordered map

pybind11/stl.h

std::set<T>

STL ordered set

pybind11/stl.h

std::unordered_set<T>

STL unordered set

pybind11/stl.h

std::optional<T>

STL optional type (C++17)

pybind11/stl.h

std::experimental::optional<T>

STL optional type (exp.)

pybind11/stl.h

std::variant<...>

Type-safe union (C++17)

pybind11/stl.h

std::filesystem::path<T>

STL path (C++17) 1

pybind11/stl/filesystem.h

std::function<...>

STL polymorphic function

pybind11/functional.h

std::chrono::duration<...>

STL time duration

pybind11/chrono.h

std::chrono::time_point<...>

STL date/time

pybind11/chrono.h

Eigen::Matrix<...>

Eigen: dense matrix

pybind11/eigen.h

Eigen::Map<...>

Eigen: mapped memory

pybind11/eigen.h

Eigen::SparseMatrix<...>

Eigen: sparse matrix

pybind11/eigen.h

1

std::filesystem::path is converted to pathlib.Path and os.PathLike is converted to std::filesystem::path.