Basic types
C++ has a far richer set of builtin types than Python.
Most Python code can remain relatively agnostic to that, and cppyy
provides automatic conversions as appropriate.
On the other hand, Python builtin types such as lists and maps are far
richer than any builtin types in C++.
These are mapped to their Standard Template Library equivalents instead.
The C++ code used for the examples below can be found
here, and it is assumed that that code is
loaded before running any of the example code snippets.
Download it, save it under the name features.h
, and simply include it:
>>> import cppyy >>> cppyy.include('features.h') >>>
Builtins
The selection of builtin data types varies greatly between Python and C++.
Where possible, builtin data types map onto the expected equivalent Python
types, with the caveats that there may be size differences, different
precision or rounding, etc.
For example, a C++ float
is returned as a Python float
, which is in
fact a C++ double
.
If sizes allow, conversions are automatic.
For example, a C++ unsigned int
becomes a Python2 long
or Python3
int
, but unsigned-ness is still honored:
>>> cppyy.gbl.gUint 0L >>> type(cppyy.gbl.gUint) <type 'long'> >>> cppyy.gbl.gUint = -1 Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: cannot convert negative integer to unsigned >>>
On some platforms, 8-bit integer types such as int8_t
and uint8_t
are
represented as char types.
For consistency, these are mapped onto Python int.
Some types are builtin in Python, but (STL) classes in C++.
Examples are str
vs. std::string
(see also the
Strings section) and complex
vs. std::complex
.
These classes have been pythonized to behave the same wherever possible.
For example, string comparison work directly, and std::complex
has
real
and imag
properties:
>>> c = cppyy.gbl.std.complex['double'](1, 2) >>> c (1+2j) >>> c.real, c.imag (1.0, 2.0) >>> s = cppyy.gbl.std.string("aap") >>> type(s) <class cppyy.gbl.std.string at 0x7fa75edbf8a0> >>> s == "aap" True >>>
To pass an argument through a C++ char
(signed or unsigned) use a Python
string of size 1.
In many cases, the explicit C types from module ctypes
can also be used,
but that module does not have a public API (for type conversion or otherwise),
so support is somewhat limited.
There are automatic conversions between C++’s std::vector
and Python’s
list
and tuple
, where possible, as they are often used in a similar
manner.
These datatypes have completely different memory layouts, however, and the
std::vector
requires that all elements are of the same type and laid
out consecutively in memory.
Conversion thus requires type checks, memory allocation, and copies.
This can be rather expensive.
See the section on STL.
Arrays
Builtin arrays are supported through arrays from module array
(or any
other builtin-type array that implements the Python buffer interface, such
as numpy arrays) and a low-level view type from cppyy
for returns and
variable access (that implements the buffer interface as well).
Out-of-bounds checking is limited to those cases where the size is known at
compile time.
Example:
>>> from cppyy.gbl import Concrete >>> from array import array >>> c = Concrete() >>> c.array_method(array('d', [1., 2., 3., 4.]), 4) 1 2 3 4 >>> c.m_data[4] # static size is 4, so out of bounds Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: buffer index out of range >>>
Arrays of arrays are supported through the C++ low-level view objects. This only works well if sizes are known at compile time or can be inferred. If sizes are not known, the size is set to a large integer (depending on the array element size) to allow access. It is then up to the developer not to access the array out-of-bounds. There is limited support for arrays of instances, but those should be avoided in C++ anyway:
>>> cppyy.cppdef('std::string str_array[3][2] = {{"aa", "bb"}, {"cc", "dd"}, {"ee", "ff"}};') True >>> type(cppyy.gbl.str_array[0][1]) <class cppyy.gbl.std.string at 0x7fd650ccb650> >>> cppyy.gbl.str_array[0][1] 'bb' >>> cppyy.gbl.str_array[4][0] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: tuple index out of range >>>
Pointers
When the C++ code takes a pointer or reference type to a specific builtin
type (such as an unsigned int
for example), then types need to match
exactly.
cppyy
supports the types provided by the standard modules ctypes
and
array
for those cases.
Example of using a reference to builtin:
>>> from ctypes import c_uint >>> u = c_uint(0) >>> c.uint_ref_assign(u, 42) >>> u.value 42 >>>
For objects, an object, a pointer to an object, and a smart pointer to an object are represented the same way, with the necessary (de)referencing applied automatically. Pointer variables are also bound by reference, so that updates on either the C++ or Python side are reflected on the other side as well.
Enums
Named, anonymous, and class enums are supported.
The Python-underlying type of an enum is implementation dependent and may even
be different for different enums on the same compiler.
Typically, however, the types are int
or unsigned int
, which
translates to Python’s int
or long
on Python2 or class int
on
Python3.
Separate from the underlying, all enums have their own Python type to allow
them to be used in template instantiations:
>>> from cppyy.gbl import kBanana # classic enum, globally available >>> print(kBanana) 29 >>> cppyy.gbl.EFruit <class '__main__.EFruit'> >>> print(cppyy.gbl.EFruit.kApple) 78 >>> cppyy.gbl.E1 # C++11 class enum, scoped Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: <namespace cppyy.gbl at 0x7ff2766a4af0> has no attribute 'E1'. >>> cppyy.gbl.NamedClassEnum.E1 42 >>>