2011-11-25 3 views
6

완벽한 포워딩에 어려움이 있습니다.퍼펙트 포워딩 및 std :: tuple (또는 다른 템플릿 클래스)

다음은 현재 이해 수준입니다. glue Template + rvalue reference + std :: forward 및 특수 마법 모드는 템플릿 공제 규칙이 평소와 같은 의미는 아니지만 완벽하게 전달할 수 있도록 제작되었습니다. 예 :

template <typename T> 
void outer(T&& t) 
{ 
    inner(std::forward<T>(t)); // perfect forwarding activated 
} 

하지만 T가 실제로 템플릿 기반 클래스 인 경우 어떻게됩니까? 예를 들어, std :: tuple을 완벽하게 전달하려면 어떻게해야합니까? T & &을 aboce로 사용하면 튜플에 포함 된 개체의 모든 유형 정보가 손실됩니다.
다음과 같은 코드가 작동하지 않을 수 있습니다 그러나 :

template <typename... Args> 
void outer(std::tuple<Args...>&& t) 
{ 
    inner(std::forward<std::tuple<Args...>>(t)); 
    use_args_types_for_something_else<Args...>(); // I need to have Args available 
} 

int main() 
{ 
    std::tuple<int, double, float> t(4, 5.0, 4.0f); 
    outer(t); 
} 

마지막 GCC 스냅 샷은 말한다 :

error: cannot bind 'std::tuple<int, double, float> lvalue to 
std::tuple<int, double, float>&& 

를 그래서 명확하게, 우리가 일반적으로 템플릿이 아닌 경우에 여전히있는 곳 좌변은 바인딩 할 수 없습니다 rvalue reference에. "완벽한 forwading 모드"

그래서 나는 몰래하고 템플릿 템플릿으로 내 튜플을 통과하려 활성화되지 않은 :

template < 
    typename... Args 
    template <typename...> class T 
> 
void outer(T<Args...>&& t) 
{ 
    inner(std::forward<T<Args...>>(t)); 
    use_args_type_for_something_else<Args...>(); 
} 

을하지만 난 여전히 같은 오류가 발생합니다. 이 때문에

template <typename T> 
void outer(T&& t) 
{ 
    inner(std::forward<T>(t)); // perfect forwarding activated 
} 

위 작품 : 매개 변수의 유형이 기능을위한 템플릿 유형은, 그래서 완벽한 전달을 달성하는 유일한 방법은 첫 번째 예와 같은 경우에만

+0

유형을 지정하지 않고 std :: forward를 호출 할 수는 없습니까 (템플릿 함수이고 공제를 사용할 수 있습니까?). 'std :: forward (t)' – SoapBox

답변

3

완벽한 전달이 작동 특수한 경우 TSomeType& 또는 SomeType&&으로 추론됩니다.

그러나 이것은 튜플 요소의 형식 정보가 손실되었다는 의미는 아닙니다. 여전히 검색 할 수 있습니다 (비록 당신이 variadic 템플릿 팩을 typedef 할 수 있다고는 생각하지 않지만).

template <class T> 
struct call_uses_args; 

template <class ...Args> 
struct call_uses_args<std::tuple<Args...>> 
{ 
    void call() const { use_args_types_for_something_else<Args...>(); } 
}; 

template <typename TupleT> 
void outer(TupleT&& t) 
{ 
    inner(std::forward<TupleT>(t)); 
    call_uses_args<typename std::remove_reference<TupleT>::type>().call(); 
} 

하지만, 좋은 일반적인 솔루션이 없을 수도 있지만 잘하면 이러한 상황은 드문 예를 들어, 당신은 여전히 ​​같은 use_args_types_for_something_else 호출 할 수 있습니다. 예를 들어이 특정 예에서는 outer을 오버로드하는 것이 더 간단 할 수 있습니다.

+0

당신의 친절하고 정답을 보내 주셔서 감사합니다. 그래서 완벽한 포워딩에 관한 C++ 11, 나는 여전히이 이상한 콤보 "template + rref + std :: forward"에 너무 많이 의존한다는 것을 조금은 느끼고 있습니다. 일반적인 규칙 (예 : "rvalue 참조가 단지 rvalue에 바인딩 됨")이 더 이상 적용되지 않는 작은 지점을 만듭니다. 완벽한 포워딩을위한 특별한 구문이 C++ 11에서 더 우수하지 않았을까? 어쨌든,이 경우의 해결 방법은 'outer'에 대해 두 가지 과부하를 만들 수 있기 때문에 큰 문제가되지 않습니다. 하나는 const를, 다른 하나는 rref를 사용하여 PF를 에뮬레이션합니다. –

관련 문제