将C++向量转换为Julia向量

4
julia> using Cxx
julia> cxx""" #include <vector> """
true
julia> cxx""" std::vector<int> a = std::vector<int> (5,6); """
true
julia> icxx""" a[0]; """
(int &) 6
julia> b = icxx""" a; """
(class std::vector<int, class std::allocator<int> >) {
}
julia> b[0]
6
julia> b
(class std::vector<int, class std::allocator<int> >) {
}

当以上的代码输入到Julia终端时,会显示向量数据已存在。但是,我更喜欢将其完全转换为Julia数组。最佳方法是什么?

注意:最终,一个共享库将返回一个std::vector<int>,因此问题更明确,即如何最好地将std::vector<int>转换为标准的Julia向量(这指的是示例代码中的变量b)。

提前致谢。

编辑:似乎对于为什么存在问题的原因不是很清楚,因此希望以下内容能够帮助(紧接着上面的代码)。

julia> unsafe_wrap(Array, pointer(b), length(b))
ERROR: MethodError: objects of type Ptr{Int32} are not callable
julia> @cxx b;
ERROR: Could not find `b` in translation unit
julia> cxx" b; "
In file included from :1:
__cxxjl_17.cpp:1:2: error: C++ requires a type specifier for all declarations
 b; 
 ^
true
julia> icxx" b; "
ERROR: A failure occured while parsing the function body
julia> cxx" &b; "
In file included from :1:
__cxxjl_15.cpp:1:3: error: C++ requires a type specifier for all declarations
 &b; 
  ^
__cxxjl_15.cpp:1:3: error: declaration of reference variable 'b' requires an initializer
 &b; 
  ^
true
julia> icxx" &b; "
ERROR: A failure occured while parsing the function body
julia> @cxx &b;
LLVM ERROR: Program used external function 'b' which could not be resolved!

无论你如何尝试传递Julia引用变量,它都无法解析回C++环境(最后一个完全破坏了Julia)。也不能使用将C++引用传递到Julia的相同方法。尝试抓取b@bb[0]&b[0]的指针并解析这些内容是可行的。

1
阅读 test/std.jl。然后执行 v = icxx"std::vector<int32_t>{2, 4, 6, 8, 10, 12, 14};",接着使用 unsafe_wrap(Array, pointer(v), length(v)) 就可以正常工作了。 - Isaiah Norton
@Isaiah 是的,这是可行的,因为变量引用从 c++ 空间开始并移动到 julia 空间。在 Cxx.j 的文档中,示例 8 鼓励将 c++ 变量直接存储为 julia 引用(在 julia 空间中)。从这里开始,似乎不可能将数据转换为标准的 julia 数组。你的示例类似于变量 a,而问题所在是变量 b 的转换。 - user3303504
3个回答

6
如果复制数据是可以接受的,您可以在C++向量上调用collect将其复制到Julia向量中。如果要避免复制,则可以使用icxx"&a[0];"获取数据的地址,并使用unsafe_wrap进行包装。

如果可能的话,我宁愿不复制数据。第二个答案(icxx"&a[0];")并不完全符合我的问题。我试图转换变量b。我尝试使用g(x,y,z) = unsafe_wrap(Array, convert(Ptr{x}, pointer_from_objref( y ) ), z, false)来调整答案,但没有成功。地址看起来是正确的,而且单独使用这种方法也是有效的。但是我无法对它们进行迭代。有什么想法吗? - user3303504
在问题中提供更多细节。 - user3303504
你需要将&a[0]的结果作为指针参数传递给unsafe_wrap。如果你索引向量,那么会提取一个整数,然后你将包装一个指向该整数对象的指针,这不是你想要的。 - Jeff Bezanson
经过一番摸索,我得出结论,只有当变量在“cxx空间”中时才可能实现。这意味着无法转换变量b,但可以转换a。我正在编写一些示例代码,以便更容易地向其他人解释我的用例,不过,就所有目的而言,我会将您的答案标记为正确的。感谢您的帮助 =) - user3303504
2
你尝试过 unsafe_wrap(Array, icxx"&a[0];", 5, false) 吗?函数 pointer_from_objref 获取Julia对象的地址,因此在这些情况下通常不是您想要的。在C++中,&a[0] 已经返回了您想要的指针;pointer_from_objref 将为您提供表示该指针的Julia对象的地址。经验法则是,如果您已经有一个指针,请不要调用 pointer_from_objref - Jeff Bezanson
显示剩余2条评论

4

感谢Jeff Bezanson和Isaiah的回答(分别为icxx" &a[0]; "sum = icxx""" std::accumulate($b.begin(), $b.end(), 0); """

为了将所有内容合并为一个答案,我制作了以下示例:

# Converting between Julia and C++
using Cxx
cxxinclude("vector")
cxx" std::vector<int> a = std::vector<int> (5,6); "
 # Transfer variable from C++ space to julia space "as is"
b = @cxx a;

# Pass the raw data reference from the C++ variable into julia space
c = icxx" &a[0]; " # From C++ space
d = icxx" &$b[0]; " # From julia space, only difference is the '$' interpolation

# Get the number of elements in the vector
cSize = icxx" a.size(); "
dSize = icxx" $b.size(); "

# Convert to a standard julia array
juliaArray_c = unsafe_wrap(Array, c, cSize, true)
juliaArray_d = unsafe_wrap(Array, d, dSize, true).

希望这能帮助到其他处于相同情况的人。

0
这里的问题对我仍不清楚,但回应编辑:要将一个CppValue Julia变量传回到icxx,请使用插值。例如:
julia> cxx""" std::vector<int> a = std::vector<int> (5,6); """
true

julia> b = @cxx a
(class std::__1::vector<int, class std::__1::allocator<int> >) {
}

julia> typeof(b)
Cxx.CppValue{Cxx.CxxQualType{Cxx.CppTemplate{Cxx.CppBaseType{Symbol("std::__1::vector")},Tuple{Int32,Cxx.CxxQualType{Cxx.CppTemplate{Cxx.CppBaseType{Symbol("std::__1::allocator")},Tuple{Int32}},(false, false, false)}}},(false, false, false)},24}

julia> cxxinclude("numeric")

julia> sum = icxx""" std::accumulate($b.begin(), $b.end(), 0); """
30

关于“空格”,我不认为示例8或文档总体上对变量声明做出规范性陈述,但一般来说,Julia引用可能更方便与Julia代码一起使用。Jeff答案中给出的示例是制作无复制包装器的解决方案。要使用声明为std::vector的数据,我知道的选项有:复制、包装指针或使用提供的getindex重载将数据视为(基于0的)Julia数组(它会自动进行指针包装,并且不应该有任何开销)。

1
啊!插值法真的很重要。如果你在回答中添加 julia> ptr = icxx""" &$b[0]; """julia> size = icxx""" $b.size(); """juliaArray = unsafe_wrap(Array, ptr, size, true),那么它就完美地回答了我的原始问题。谢谢 =) - user3303504

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接