【问题标题】:C++ templated functor in lambda expressionlambda 表达式中的 C++ 模板化函子
【发布时间】:2010-02-26 18:03:22
【问题描述】:

下面的 Eric 的 cmets 解决了第一个问题,但导致了我在水平规则之后描述的次要问题。谢谢埃里克!

我正在尝试将作为模板类的仿函数与两个参数一起传递给 boost thread_group 类的 create_thread 方法。但是我似乎无法超越我当前的编译错误。使用以下代码:

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/thread.hpp>
#include <vector>

using namespace boost::lambda;
using namespace std;

namespace bl = boost::lambda;

template<typename ftor, typename data>
class Foo
{
public:
    explicit Foo()
    {
    }
    void doFtor ()
    {
        _threads.create_thread(bind(&Foo<ftor, data>::_ftor, _list.begin(), _list.end()));
        //_threads.create_thread(bind(_ftor, _list.begin(), _list.end()));
        _threads.join_all();
    }

private:
    boost::thread_group _threads;
    ftor _ftor;
    vector<data> _list;
};

template<typename data>
class Ftor
{
public:
    //template <class Args> struct sig { typedef void type; }

    explicit Ftor () {}

    void operator() (typename vector<data>::iterator &startItr, typename vector<data>::iterator &endItr)
    {
        for_each(startItr, endItr, cout << bl::_1 << constant("."));
    }
}

我还尝试了 typedef-ing 'type',因为我认为我的问题可能与 Sig 模板有关,因为函子本身是模板化的。

我得到的错误是:

error: no matching function for call to ‘boost::lambda::function_adaptor<Ftor<int> Foo<Ftor<int>, int>::*>::apply(Ftor<int> Foo<Ftor<int>, int>::* const&, const __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>> >&, const __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >&)’

事先有一堆序言。

提前感谢您的帮助!


好的,我根据 Eric 的建议修改了代码,得到了以下代码:

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/thread.hpp>
#include <vector>

using namespace boost::lambda;
using namespace std;

namespace bl = boost::lambda;

template<typename ftor, typename data>
class Foo
{
public:
    explicit Foo()
    {
    }
    void doFtor ()
    {
        _threads.create_thread(bl::bind(boost::ref(_ftor), _list.begin(), _list.end()));
        _threads.join_all();
    }

private:
    boost::thread_group _threads;
    ftor _ftor;
    vector<data> _list;
};

template<typename data>
class Ftor
{
public:
    typedef void result_type;

    explicit Ftor () {}

    result_type operator() (typename vector<data>::iterator &startItr, typename vector<data>::iterator &endItr)
    {
        for_each(startItr, endItr, cout << bl::_1 << constant("."));
        return ;
    }
};

但是这会导致另一个编译错误:

/usr/local/include/boost/lambda/detail/function_adaptors.hpp:45: error: no match for call to ‘(Ftor<int>) (const __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >&, const __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >&)’
ftor.h:41: note: candidates are: void Ftor<data>::operator()(typename std::vector<data, std::allocator<_CharT> >::iterator&, typename std::vector<data, std::allocator<_CharT> >::iterator&) [with data = int]
/usr/local/include/boost/lambda/detail/function_adaptors.hpp:45: error: return-statement with a value, in function returning 'void'

似乎已经将 void 定义为 result_type 它现在期望 operator() 返回一些东西。我尝试从函数中返回 result_type ,但这也产生了错误。有什么想法吗?

【问题讨论】:

  • 您使用的是什么编译器以及什么版本的 boost?这里编译得很好,只是缺少 iostream 标头(GCC 4.3.3,boost 1.42)
  • 有趣。我在我的 Mac 上试过这个,不确定 gcc 版本,但它使用 boost 1.42。我已经在我的 linux 机器上复制了它,它使用了稍微旧的版本:gcc 4.1.1 和 boost 1.37
  • 所示代码可以编译,但实例化Foo::doFtor()会导致编译错误。例如,尝试添加int main(){Foo&lt;Ftor&lt;int&gt;, int&gt; f; f.doFtor();}
  • 啊,是的,我也应该提供我的主要内容。除非实例化/调用,否则编译器不会为 doFtor 方法生成代码。
  • 要清楚,这是对我有用的代码:codepad.org/j4mibHWS

标签: c++ templates lambda functor


【解决方案1】:

Sig(或者在您的情况下,只需 typedef void result_type; 是必要的。

IIRC,lambda::bind 对其参数进行 const 副本。

因此,具有非常量 operator() 的函子存在问题。这可以通过使 Ftor::operator()const 通过包装(在 doFtor() 中)、_ftor 和 boost::ref

来解决

迭代器也有类似的问题。在这里包装 boost::ref 不会直接起作用,因为它最终会使用对临时的引用。更简单的解决方案是修改 Ftor::operator() 以通过副本获取其参数。

因此,最简单的方法是修改 Ftor,使其 operator() 为 const 并且它通过副本获取其参数:

void operator() (typename vector<data>::iterator startItr, typename vector<data>::iterator endItr)const

如果你真的不能让 Ftor::operator() 为 const,你可以修改 doFtor() 如下(但仍然需要让 Ftor::operator() 以副本的方式获取它的参数):

_threads.create_thread(bind(boost::ref(_ftor), _list.begin(), _list.end()));

【讨论】:

  • 通过选项 2 中提到的更改,我得到以下信息:- 错误:在传递 'const boost::reference_wrapper boost::ref(T&) 的参数 1 [with T = __gnu_cxx: :__normal_iterator > >]'
  • 确实,在 _list.begin() 上使用 boost::ref 并不是一个好主意,因为它最终会传递对临时对象的引用。我会更新答案
  • @Eric:我按照您的建议修改了代码,但这也会产生编译错误。这次返回类型我认为归结为 typedef。我已经修改了上面的问题以反映这些变化。
猜你喜欢
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多