如何使用variadic完美转发到lambda?

kfm*_*e04 18 c++ lambda binding variadic-templates c++11

我有一个调用lambda的工作函数模板.

我想概括这个函数模板来获取可变参数并将它们完美地转发到lambda中,但是我无法编译这段代码.

我正在使用gcc 4.7.2.

UPDATE

使用R. Martinho Fernandes的建议,我查找了bugzilla中的错误 - 它看起来像一个已经存在一段时间的bug.如果有人知道一个解决方法(我现在正在挖掘一个),请发一个答案 - ty.

错误

junk.cpp: In lambda function:
junk.cpp:32:68: error: parameter packs not expanded with ‘...’:
junk.cpp:32:68: note:         ‘args’
junk.cpp: In instantiation of ‘std::pair<std::basic_string<char>, typename T::Lambda> MP(const string&, M, Args&& ...) [with T = Integer; M = int (Integer::*)()const; Args = {}; typename T::Lambda = std::function<std::function<int()>(const Integer&)>; std::string = std::basic_string<char>]’:
junk.cpp:47:42:   required from here
junk.cpp:34:2: error: using invalid field ‘MP(const string&, M, Args&& ...)::<lambda(const T&)>::__args’
make: *** [junk] Error 1
Run Code Online (Sandbox Code Playgroud)

#include <functional>
#include <iostream>
#include <map>

struct Integer
{
    typedef std::function<int()>                            Function;
    typedef std::function<Function( Integer const& inst )>  Lambda;

    virtual int getInt() const = 0;
};

struct IntImpl : public Integer
{
    virtual int getInt() const { return 42; }
};

typedef std::function<int()>                               IntFunction;
typedef std::function<IntFunction( Integer const& inst )>  IntLambda;

#define WONT_COMPILE

template<typename T,typename M,typename... Args>
std::pair<std::string,typename T::Lambda>
MP( std::string const& str, M method, Args&&... args )
{
#ifdef WONT_COMPILE 
    return std::make_pair( str, 
        [=]( T const& inst ) 
        {
            // COMPILE ERROR (Line 32) on next line
            return std::bind( method, std::cref( inst ), std::forward<Args>(args)...);
        } 
    );
#else
    return std::make_pair( str, 
        [method]( T const& inst ) 
        {
            return std::bind( method, std::cref( inst ));
        } 
    );
#endif
}

std::map<std::string,IntLambda> const g_intTbl =
{
    MP<Integer>( "getInt", &Integer::getInt )
};

int
main( int argv, char* argc[] )
{
    IntImpl x;
    std::cerr << g_intTbl.find("getInt")->second( x )() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

sya*_*yam 12

如果有人知道一个解决方法(我现在正在挖掘一个),请发一个答案

我遇到了完全相同的问题并找到了解决方法.这是一个迟到的答案,希望你在此期间找到了解决方案,但无论如何它在这里(它至少对其他人有用).

我们的想法是更改lambda的参数,以便它也接受与外部函数(例如,[](int) {}变为[](int, Args&&... args) {})相同的可变参数,并将lambda接受到bind外部函数的可变参数.完成此操作后,在lambda中转发可变参数不再有问题.

把它们加起来:

template<typename... Args>
std::function<void (int)> foo(Args&&... args) {
    return [&](int bar) {
                  // COMPILER BUG: doesn't work with GCC 4.7 despite the capture
                  doSomething(bar, std::forward<Args>(args)...);
              };
}

template<typename... Args>
std::function<void (int)> foo(Args&&... args) {
    return std::bind([](int bar, Args&&... args) {
                            // now this works with GCC 4.7
                            doSomething(bar, std::forward<Args>(args)...);
                       },
                     std::placeholders::_1, std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)

当然这是一个丑陋的黑客,但至少你仍然可以获得预期的功能,即使你遇到了一个错误的编译器.


R. *_*des 7

这似乎是编译器的错误(如果尚未报告,请报告).标准说:

包扩展由一个图案和省略号,实例化,其中产生所述图案的零个或多个实例中的列表(下面描述)的.模式的形式取决于扩展发生的环境.包扩展可以在以下上下文中发生:

- [...]
- 在捕获列表中(5.1.2); 模式是捕获.
- [...]

这使您的代码正确.

在您获得可以处理此问题的编译器之前,您将捕获所有内容作为变通方法[=].