Подтвердить что ты не робот

Как использовать переменную совершенную пересылку в лямбда?

У меня есть шаблон рабочей функции, который вызывает лямбда.

Я хотел бы обобщить этот шаблон функции, чтобы принимать вариативные аргументы и отлично пересылать их в лямбда, но мне сложно скомпилировать этот код.

Я использую gcc 4.7.2.

UPDATE

Используя предложение Р. Мартиньо Фернандеса, я искал ошибку в bugzilla - он выглядит как ошибка, которая была вокруг какое-то время. Если кто-нибудь знает об обходном пути (я сейчас копаю для одного), отправьте ответ.

ОШИБКИ

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

CODE

#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;
}
4b9b3361

Ответ 1

Если кто-нибудь знает об обходном пути (я сейчас копаю для одного), отправьте ответ

Я столкнулся с одной и той же проблемой и нашел обходное решение. Это своего рода поздний ответ, надеюсь, что вы нашли решение в то же время, но здесь оно в любом случае (оно может, по крайней мере, быть полезным для других).

Идея состоит в том, чтобы изменить параметры лямбда так, чтобы она также принимала те же самые вариационные аргументы, что и внешняя функция (например. [](int) {} становится [](int, Args&&... args) {}) и bind лямбда для переменных аргументов внешней функции. Как только это будет сделано, больше проблем не будет пересылка вариационных аргументов внутри лямбда.

Подводя итог:

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)...);
}

Уверен, что это уродливый взлом, но по крайней мере вы все равно можете получить намеченные функции, даже если вы застряли в компиляторе с ошибкой.

Ответ 2

Это, по-видимому, является ошибкой компилятора (просьба сообщить об этом, если он еще не был). В стандарте говорится:

Расширение пакета состоит из шаблона и многоточия, экземпляр которого производит ноль или более экземпляров шаблон в списке (описано ниже). Форма шаблона зависит от в контексте, в котором происходит расширение. Расширения пакета могут происходят в следующих контекстах:

- [...]
- в списке захвата (5.1.2); шаблон - это захват.
- [...]

Это делает ваш код правильным.

Пока вы не получите компилятор, который может справиться с этим, у вас будет захват всего в качестве обходного пути с помощью [=].