Boost转换迭代器和C++11 Lambda

12

我正在尝试使用boost::adaptors::transformed通过向适配器提供一个C++0x lambda函数来进行转换。

以下代码无法编译。我正在使用带有boost 1.48的g++ 4.6.2。

#include <iostream>
#include <vector>

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>

using namespace std;
namespace br    = boost::range;
namespace badpt = boost::adaptors;


int main()
{  
  vector<int> a = {0,3,1,};
  vector<int> b = {100,200,300,400};

  auto my_ftor = [&b](int r)->int{return b[r];};

  cout<<*br::max_element(a|badpt::transformed(my_ftor))<<endl;
}

我在这里做错了什么?


与https://dev59.com/FWcs5IYBdhLWcg3wp1z3相关的内容可能是重复的。 - ForEveR
错误日志非常详细。请查看链接:http://pastebin.com/grsENb1m。 - Nithin
3个回答

9

1
你好,据我所知,这适用于boost 1.51及以上版本。我尝试在包含任何boost头文件之前插入宏,但没有效果。链接中的其他解决方案也假定boost/range/regular.hpp可用,但在boost-1.48中不可用。感谢提供链接。 - Nithin
1
@Nithin 这个宏修复了更多的错误,但是有些错误无法在没有重写 boost::range 的情况下修复(例如默认构造函数构造函数符(boost 版本 1.48)将永远无法与闭包一起使用)。现在不要在 boost::transform_iterator 中使用闭包。 - ForEveR
哦,好的!感谢您的建议。我可能会采纳@Paul的建议,因为我现在真的无法更改boost版本。 - Nithin
请注意,从Boost 1.55开始,BOOST_RESULT_OF_USE_DECLTYPE可能会破坏boost::spirit和可能的boost::fusion - Elliot Cameron
这可能是一个众所周知的问题,但对我来说并不知道。昨天是我第一次尝试使用transform_iterator,我花了很长时间才弄清楚我的编译器在告诉我什么。当然,我假设我正在尝试做一些愚蠢的事情,所以这个答案正是我需要看到的。 - Michael Burr

4

由于Lambda表达式不具备默认构造函数,而迭代器需要默认构造函数,因此它们不够兼容。以下是我用于Lambda表达式的包装器:

#define RETURNS(...) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); }

template<class Fun>
struct function_object
{
    boost::optional<Fun> f;

    function_object()
    {}
    function_object(Fun f): f(f)
    {}

    function_object(const function_object & rhs) : f(rhs.f)
    {}

    // Assignment operator is just a copy construction, which does not provide
    // the strong exception guarantee.
    function_object& operator=(const function_object& rhs)
    {
        if (this != &rhs)
        {
            this->~function_object();
            new (this) function_object(rhs);
        }
        return *this;
    }

    template<class F>
    struct result
    {};

    template<class F, class T>
    struct result<F(T)>
    {
        typedef decltype(std::declval<Fun>()(std::declval<T>())) type;
    };

    template<class T>
    auto operator()(T && x) const RETURNS((*f)(std::forward<T>(x)))

    template<class T>
    auto operator()(T && x) RETURNS((*f)(std::forward<T>(x)))
};

template<class F>
function_object<F> make_function_object(F f)
{
    return function_object<F>(f);
}

然后您只需执行以下操作:
int main()
{  
  vector<int> a = {0,3,1,};
  vector<int> b = {100,200,300,400};

  cout<<*br::max_element(a|badpt::transformed(make_function_object([&b](int r)->int{return b[r];};)))<<endl;
}

2

@ForEver的答案(#define BOOST_RESULT_OF_USE_DECLTYPE)对我不起作用。 而@Paul的答案太长了(也太笼统了)。 一个更具体的解决方案可以是:

#include <iostream>
#include <vector>

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>

using namespace std;
namespace br    = boost::range;
namespace badpt = boost::adaptors;


int main()
{  
  vector<int> a = {0,3,1,};
  vector<int> b = {100,200,300,400};

  struct{
     vector<int>* bP;                               //pointer, just to imitate lambda syntax...
     int operator()(int r) const{return (*bP)[r];}  //was my_ftor = [&b](int r)->int{return b[r];};
  } my_ftor{&b};                                    //...here

  cout<<*br::max_element(a|badpt::transformed(my_ftor))<<endl;
}

现在已经是2016年,Boost 1.58仍然存在问题。至少没有捕获的lambda应该满足boost::transformed的要求。

如果lambda没有捕获(不是你的情况),代码会更简单一些,或者你可以使用:

...
int(*my_ftor)(int) = [](int r)->int{return ...;}; // function pointer default constructible and callable
cout<<*br::max_element(a|badpt::transformed(my_ftor))<<endl;
...

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