将 SWIG 与 C++ 模板函数一起使用

Posted

技术标签:

【中文标题】将 SWIG 与 C++ 模板函数一起使用【英文标题】:Using SWIG with C++ template functions 【发布时间】:2016-05-22 09:58:46 【问题描述】:

我有一些 c++ 中的 map 模板函数,我想在 ruby​​ 中使用它们。

template <class Collection>
const typename Collection::value_type::second_type& FindWithDefault(
    const Collection& collection,
    const typename Collection::value_type::first_type& key,
    const typename Collection::value_type::second_type& value) 
  typename Collection::const_iterator it = collection.find(key);
  if (it == collection.end()) 
    return value;
  
  return it->second;

在 c++ 中它是这样工作的

int main(int argc, char const *argv[])

    typedef std::map<std::string, std::string> Map;
    Map m;
    std::string d= FindWithDefault(m, "foo", "");
    std::cout << d << "\n";
    //    
    m["foo"] = "bar";
    d=  FindWithDefault(m, "foo", "");
    std::cout << d << "\n";
    // bar

通过查看我之前回答的问题的答案(看看here),它很容易使用map和set in ruby​​。

至于这个问题我的接口文件有这个

%include <std_map.i>
namespace std 
   %template(IntMap) map<int,int>;

template <typename Collection>
const typename Collection::value_type::second_type& FindWithDefault(
    const Collection& collection,
    const typename Collection::value_type::first_type& key,
    const typename Collection::value_type::second_type& value) ;
%template(d) FindWithDefault<std::map<int,int> >;

我的c++头文件有上面提到的完整功能。现在,当我尝试在 Irb 中进行检查时,地图工作正常,但使用模板函数时出现错误

2.2.1 :001 > a = Example::IntMap.new
 => std::map<int,int,std::less< int >,std::allocator< std::pair< int const,int > > >  
2.2.1 :002 > a[1]=2
 => 2 
2.2.1 :003 > a[5]=3
 => 3 
2.2.1 :004 > a[4]=11
 => 11 
2.2.1 :005 > a
 => std::map<int,int,std::less< int >,std::allocator< std::pair< int const,int > > > 1=>2,4=>11,5=>3 
2.2.1 :006 > b=Example::d(a,2,2)
ArgumentError: Wrong arguments for overloaded method 'd'.
Possible C/C++ prototypes are:
    std::map< int,int,std::less< int >,std::allocator< std::pair< int const,int > > >::value_type::second_type const & d(int a, int b)
    std::map< int,int,std::less< int >,std::allocator< std::pair< int const,int > > >::value_type::second_type const & d(std::map< int,int,std::less< int >,std::allocator< std::pair< int const,int > > > const &collection, std::map< int,int,std::less< int >,std::allocator< std::pair< int const,int > > >::value_type::first_type const &key, std::map< int,int,std::less< int >,std::allocator< std::pair< int const,int > > >::value_type::second_type const &value)

    from (irb):6:in `d'
    from (irb):6
    from /usr/share/rvm/rubies/ruby-2.2.1/bin/irb:11:in `<main>'

我怎样才能做到这一点?

【问题讨论】:

(回应之前的评论:问题标题是向用户传达内容的主要机制。使用您的帖子与社区的其他成员是主要的Stack Overflow 的价值,因此一个含糊不清且不太可能被有相同问题的人搜索的标题是投反对票的一个很好的理由:这意味着该帖子对社区的价值很低。这不是个人的,只是一种确定优先级的方法。) 我很抱歉猛烈抨击。 *** 是一个很棒的地方,我已经使用了很长一段时间了。但我真的很惊讶,可以通过一次谷歌搜索解决的幼稚问题获得最高票数,而许多合法和复杂的问题却没有得到解答。看看我问过***.com/questions/36603146/… 的这个问题,尽管这个问题非常有用,但被社区完全忽略了。后来我通过阅读一篇论文发现了自己,这导致了大约 1100 倍的巨大加速。 嗯,一个问题越复杂,它的兴趣通常就越小众,无论它的智力价值或难度如何。但是这样的问题肯定不会被否决。大多数人可能根本不感兴趣。但拥有这些仍然很棒,而且随着时间的推移,它们很可能会增加投票。 【参考方案1】:

似乎 SWIG 无法确定 Collection::value_type::first_typeCollection::value_type::second_type 的类型。我不确定为什么。

在这种情况下,一个可能的解决方案/解决方法是用Collection::key_type 替换Collection::value_type::first_type,用Collection::mapped_type 替换Collection::value_type::second_type。在 SWIG 接口文件中执行此操作就足够了,即,保持 C++ 代码不变,但将其放在接口文件中:

%include <std_map.i>
namespace std 
   %template(IntMap) map<int,int>;

template <typename Collection>
const typename Collection::mapped_type& FindWithDefault(
    const Collection& collection,
    const typename Collection::key_type& key,
    const typename Collection::mapped_type& value) ;
%template(d) FindWithDefault<std::map<int,int> >;

【讨论】:

就是这样。它与value_type::first_type/value_type::second_type 斗争的原因仅仅是因为 std_map.i 似乎没有在任何地方定义它,至少对于 ruby​​ 没有。 但是 Lib/std/std_map.i 确实 typedef std::map&lt;_Key, _Tp&gt;::value_typestd::pair&lt; const _Key, _Tp &gt; here,这被用于 ruby​​(和 python)的语言特定的 std_map.i 文件使用/%包含)。我仍然很困惑为什么问题中的代码不起作用。 @m7thon 非常感谢您的回答。这真的让我免于很多麻烦。我现在只有几个问题。您是使用std_map.i 还是通过阅读文档来解决这个问题的?另外如何处理 std::map<_key _tp>::value_type 我在 std::pair 遇到一些奇怪的错误?再次感谢这个答案真的很有用 错误(由 SWIG 生成)表明需要 key 类型的 std::map&lt;int,int,... &gt;::value_type::first_type const &amp; 参数。显然,这种类型只是一个 int &amp;,而您提供了一个 int(嗯,SWIG 应该能够转换的东西)。所以,SWIG 不理解这种类型。我仍然不确定为什么。我尝试了更简单的Container::key_type,它有效。 SWIG 确实有一个出色的(虽然很长)文档,我已经查阅过很多次。了解 SWIG 基础知识至关重要。查看 SWIG 库文件和生成的包装器代码也很有见地。

以上是关于将 SWIG 与 C++ 模板函数一起使用的主要内容,如果未能解决你的问题,请参考以下文章

使用 SWIG 绑定 Python/C++ 模板

Python 错误:在 SWIG 生成的 C++ 模板代码模块中未定义构造函数

带有类型推导的 swig python 模板函数

通过 consolidate.js 获取 Node.js Express 3.x 模板继承与 Swig 一起使用的问题

C++中,怎么将函数模板的声明和定义分开写?

使用 SWIG 包装调用另一个对象成员函数的 C++ 类