2013-01-07 3 views
17

나는 람다를 호출하는 작동 함수 템플릿을 가지고있다.람다로 variadic 완벽한 전달을 어떻게 사용합니까?

이 함수 템플릿을 가변 인수를 취하여 람다로 완벽하게 전달하려면이 함수 템플릿을 일반화하고 싶지만이 코드를 컴파일하는 데 문제가 있습니다.

gcc 4.7.2를 사용하고 있습니다.

UPDATE

R. 마르틴 페르난데스의 제안을 사용하여

, 나는 버그질라에 오류를 보았다 - it does look like a bug that's been around for a while. 만약 누군가가 해결 방법을 알고 있다면 (나는 지금 한 가지를 파헤 치고있다.) 대답을 게시 해주십시오.

에러

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; 
} 
+1

'std :: forward (args ...)'이 (가)'std :: forward가되어야하기 때문에 발생하는 것으로 보인다. :: (args) ... ' –

+0

@AndreiTita +1 ty - 도움이된다. 여전히 오류가 발생합니다 - OP가 업데이트되었습니다. – kfmfe04

+1

람다 캡처에서 가변 팩을 확장 할 수 있는지 잘 모르겠지만 (잠시 후에 확인할 것입니다.) 해결 방법은 다음과 같이 전체 캡처를 사용하는 것과 같습니다. '[=]'. –

답변

7

. 표준 메시지 :

는 목록에서 패턴의 0 개 이상의 인스턴스 생성을 생산 인스턴스화되는 패턴과 생략, 으로 구성된 확장 팩 (후술). 패턴의 형식은 확장이 발생하는 컨텍스트에 에 따라 다릅니다. 팩 확장은 다음과 같은 상황에서 발생할 수 있습니다

- [...]
- 캡처 목록 (5.1.2)에서; 패턴은 캡처입니다.
- [...]

이렇게하면 코드가 정확합니다.

이 문제를 처리 할 수있는 컴파일러가 생길 때까지 [=]과 함께 모든 것을 해결 방법으로 캡처 할 수 있습니다.

+0

Heh 나는 똑같은 것을 쓰려고하고 있었다. (그러나 당신은 더 좋은 표준 인용문을 가지고있다.) 특히 그것은 gcc 버그입니다 - MSVC (11 월 CTP) 및 Clang 3.2는 람다 캡처에서 인수 팩 확장을 허용합니다. –

+0

문제에 대한 빛을 비추는 +1 : gcc 해결 방법을 아는 사람이 있다면 – kfmfe04

11

사람이 해결 방법 (지금은 하나의 주위를 파고있어) 알고 있으면 대답

나는 똑같은 문제로 실행하고 해결 방법을 찾았을 게시하시기 바랍니다. 그것은 늦은 대답의 일종입니다. 그 동안 해결책을 찾았 으면 좋겠지 만, 어쨌든 (어쨌든 그것은 다른 사람들에게 유용 할 수 있습니다). 또한 외부 기능 (예. [](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)...); 
} 

물론이 못생긴 해킹,하지만 당신은 버그가 컴파일러와 함께 붙어있을 때 적어도 당신은 여전히도 의도 된 기능을 얻을 수 있습니다 :

그것을 요약합니다.

+0

+1을 게시하여 결과를 게시하십시오. 시도해 보겠습니다. – kfmfe04

+0

서면으로 작성합니까? std :: function이'int'와'Args && ...'를 매개 변수로 사용한다는 사실을 고려하기 위해 반환 값의 서명을 변경해야한다고 생각합니다. –

+0

@Sean 아니요, 내가 게시 한 코드는있는 그대로 작동합니다. functor를 반환하기 전에'Args && ... '부분이 * bound *이기 때문에'foo'의 반환 값의 타입을 변경할 필요가 없습니다. 이것이 실제로 bind의 전체적인 요점입니다 : 바인드 된 functor의 인수를 부분적으로 적용합니다. – syam

관련 문제