cppyy 基本类型#

C++ 的内置类型比 Python 丰富得多。大多数 Python 代码对此可以相对保持不可知,cppyy 在适当的时候提供自动转换。另一方面,Python 的内置类型(如列表和映射)比 C++ 中的任何内置类型都要丰富得多。这些类型被映射到它们的标准模板库等价物。

下面的示例中使用的 C++ 代码可以在这里找到,并且假设在运行任何示例代码片段之前已经加载了该代码。下载它,将其保存为名为 features.h 的文件,然后简单地包含它:

import cppyy
cppyy.include('features.h')
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[1], line 1
----> 1 import cppyy
      2 cppyy.include('features.h')

ModuleNotFoundError: No module named 'cppyy'

cppyy 内置类型#

Python 和 C++ 之间的内置数据类型的选择差异很大。在可能的情况下,内置数据类型映射到预期的等效 Python 类型,但要注意可能存在的大小差异、不同的精度或舍入等。例如,C++ 的 float 返回为 Python 的 float,实际上是 C++ 的 double。如果大小允许,转换是自动的。例如,C++ 的 unsigned int 变成 Python2 的 long 或 Python3 的 int,但无符号性仍然保留:

cppyy.gbl.gUint
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[2], line 1
----> 1 cppyy.gbl.gUint

NameError: name 'cppyy' is not defined
type(cppyy.gbl.gUint)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[3], line 1
----> 1 type(cppyy.gbl.gUint)

NameError: name 'cppyy' is not defined
cppyy.gbl.gUint = -1
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[4], line 1
----> 1 cppyy.gbl.gUint = -1

NameError: name 'cppyy' is not defined

在某些平台上,8 位整数类型(如 int8_tuint8_t)表示为 char 类型。为了保持一致性,这些类型映射到 Python int

有些类型在 Python 中是内置的,但在 C++ 中是(STL)类。例如,strstd::string(另见字符串部分)以及 complexstd::complex。这些类已经被 python 化,以尽可能表现得相同。例如,字符串比较可以直接工作,而 std::complex 具有 realimag 属性:

c = cppyy.gbl.std.complex['double'](1, 2)
c
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 c = cppyy.gbl.std.complex['double'](1, 2)
      2 c

NameError: name 'cppyy' is not defined
c.real, c.imag
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[6], line 1
----> 1 c.real, c.imag

NameError: name 'c' is not defined
s = cppyy.gbl.std.string("aap")
type(s)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[7], line 1
----> 1 s = cppyy.gbl.std.string("aap")
      2 type(s)

NameError: name 'cppyy' is not defined
s == "aap"
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[8], line 1
----> 1 s == "aap"

NameError: name 's' is not defined

要通过 C++ 的 char(有符号或无符号)传递参数,使用大小为 1 的 Python 字符串。在许多情况下,也可以使用 ctypes 模块中的显式 C 类型,但该模块没有公共 API(用于类型转换或其他用途),所以支持有些有限。

在可能的情况下,C++ 的 std::vector 和 Python 的 listtuple 之间存在自动转换,因为它们通常以类似的方式使用。然而,这些数据类型具有完全不同的内存布局,而 std::vector 要求所有元素都是相同的类型并在内存中连续排列。因此,转换需要类型检查、内存分配和复制。这可能会相当昂贵。

tuple
tuple

cppyy 数组#

通过 array 中的数组(或任何其他实现 Python 缓冲接口的内置类型数组,如 numpy 数组)以及 cppyy 中用于返回和变量访问的低级视图类型来支持内置数组(同样实现了缓冲接口)。仅在编译时知道大小的情况下进行越界检查。示例:

from cppyy.gbl import Concrete
from array import array
c = Concrete()
c.array_method(array('d', [1., 2., 3., 4.]), 4)
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[10], line 1
----> 1 from cppyy.gbl import Concrete
      2 from array import array
      3 c = Concrete()

ModuleNotFoundError: No module named 'cppyy'
c.m_data[4] # static size is 4, so out of bounds
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[11], line 1
----> 1 c.m_data[4] # static size is 4, so out of bounds

NameError: name 'c' is not defined

cppyy 数组#

数组通过C++的低级视图对象来支持。只有在编译时知道大小或可以推断出大小时,这种方法才会有效。如果大小未知,则将大小设置为一个大整数(取决于数组元素的大小)以允许访问。然后由开发者确保不越界访问。对实例数组的支持有限,但在C++中应尽量避免使用这些:

cppyy.cppdef('std::string str_array[3][2] = {{"aa", "bb"}, {"cc", "dd"}, {"ee", "ff"}};')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[12], line 1
----> 1 cppyy.cppdef('std::string str_array[3][2] = {{"aa", "bb"}, {"cc", "dd"}, {"ee", "ff"}};')

NameError: name 'cppyy' is not defined
type(cppyy.gbl.str_array[0][1])
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[13], line 1
----> 1 type(cppyy.gbl.str_array[0][1])

NameError: name 'cppyy' is not defined
cppyy.gbl.str_array[0][1]
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[14], line 1
----> 1 cppyy.gbl.str_array[0][1]

NameError: name 'cppyy' is not defined
cppyy.gbl.str_array[4][0]
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[15], line 1
----> 1 cppyy.gbl.str_array[4][0]

NameError: name 'cppyy' is not defined

cppyy 指针#

当C++代码采用指向特定内置类型的指针或引用类型(例如,无符号整数)时,类型必须完全匹配。cppyy支持标准模块ctypes和array提供的这些类型。使用对内置类型的引用的示例:

from ctypes import c_uint
u = c_uint(0)
c.uint_ref_assign(u, 42)
u.value
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[16], line 3
      1 from ctypes import c_uint
      2 u = c_uint(0)
----> 3 c.uint_ref_assign(u, 42)
      4 u.value

NameError: name 'c' is not defined

对于对象,一个对象、指向对象的指针以及智能指针以相同的方式表示,同时自动应用必要的(解)引用。指针变量也通过引用绑定,因此C++或Python端的更新也会在另一端反映出来。

cppyy 枚举#

支持命名、匿名和类枚举。枚举的Python底层类型是实现相关的,甚至可能在同一编译器上对不同枚举有所不同。然而,通常这些类型是 intunsigned int,这会转换为 Python 的 int 或在 Python2 上的 long,或者在 Python3 上的 class int。与底层类型分开,所有枚举都有它们自己的 Python 类型,以允许它们用于模板实例化:

from cppyy.gbl import kBanana   # classic enum, globally available
print(kBanana)
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[17], line 1
----> 1 from cppyy.gbl import kBanana   # classic enum, globally available
      2 print(kBanana)

ModuleNotFoundError: No module named 'cppyy'
cppyy.gbl.EFruit
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[18], line 1
----> 1 cppyy.gbl.EFruit

NameError: name 'cppyy' is not defined
print(cppyy.gbl.EFruit.kApple)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[19], line 1
----> 1 print(cppyy.gbl.EFruit.kApple)

NameError: name 'cppyy' is not defined
cppyy.gbl.E1
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[20], line 1
----> 1 cppyy.gbl.E1

NameError: name 'cppyy' is not defined
cppyy.gbl.NamedClassEnum.E1
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[21], line 1
----> 1 cppyy.gbl.NamedClassEnum.E1

NameError: name 'cppyy' is not defined