使用SWIG与C++模板函数

3

我有几个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
}

通过查看我之前回答的问题的答案,可以很容易地在Ruby中使用map和set(请看这里)。

至于这个问题,我的接口文件如下:

%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>'

我该如何使这个工作起来?

作为对之前评论的回应:问题标题是向用户传达内容的主要机制。您的帖子向社区其他成员传递价值,因此,如果标题模糊不清,不太可能被遇到相同问题的人搜索,那么这就是一个非常好的降低投票的理由:这意味着该帖子对社区的价值很低。这并不是个人攻击,只是一种优先排序的方法。 - Kerrek SB
2
很抱歉我之前的激动。Stackoverflow是一个我已经使用了相当长时间的好地方。但我真的很惊讶,一些可以通过简单的谷歌搜索解决的幼稚问题却被投票置顶,而许多合法和复杂的问题则被无视。看看我曾经提出的这个问题https://dev59.com/GZbfa4cB1Zd3GeqPngrW,尽管它非常有用,但社区完全忽略了它。后来我自己通过阅读论文找到了答案,并实现了大约1100倍的速度提升。 - ArafatK
一个问题越复杂,它的兴趣领域通常就越小众,无论它的智力价值或难度如何。但这样的问题肯定不会被踩;它们可能只是对大多数人不感兴趣。但是拥有这些问题仍然很棒,它们随着时间的推移可能会积累起赞数。 - Kerrek SB
1个回答

2
似乎SWIG无法确定Collection::value_type::first_type和Collection::value_type::second_type的类型,我不确定原因。
在这种情况下可能的解决方法/变通方法是将Collection::value_type::first_type替换为Collection::key_type,将Collection::value_type::second_type替换为Collection::mapped_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 中似乎没有定义它,至少我没有找到。 - Flexo
但是Lib/std/std_map.i将std::map<_Key, _Tp>::value_type typedef为std::pair< const _Key, _Tp > 在这里,而且这个typedef被用于Ruby(和Python)的特定语言std_map.i文件中。我仍然困惑为什么问题中的代码不起作用。 - m7thon
3
非常感谢您的回答。这真的帮了我很大的忙。现在我只有几个问题。您是通过使用 std_map.i 还是阅读文档来解决这个问题的?另外,我该如何处理 std::map<_Key, _Tp>::value_type?我正在使用 std::pair<int,int> 时遇到一些奇怪的错误。再次感谢,这个答案真的非常有用。 - ArafatK
1
错误(由SWIG生成)告诉我们需要一个类型为std::map<int,int,...>::value_type::first_type const &key参数。显然,这个类型只是一个int &,而你提供了一个int(好吧,这应该是SWIG可以转换的)。所以,SWIG没有理解这个类型。我仍然不确定为什么。我尝试了更简单的Container::key_type,它可以工作。SWIG确实有一个很好的(虽然很长)文档,我已经多次参考过。理解SWIG的基础知识是必要的。查看SWIG库文件和生成的包装代码也非常有启发性。 - m7thon

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