2011-11-25 10 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>&& 

だから明確に、私たちは左辺値を結合することができず、一般的な、非テンプレートケースに残っていますr値参照。

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

しかし、私はまだ同じエラーを取得:「パーフェクトforwadingモードは」だから

を起動していない私は、卑劣なこととテンプレートテンプレートとして私のタプルを渡そうとしました。

+0

型を指定せずにstd :: forwardを呼び出すことはできません(テンプレート関数であり、控除を使用することができます)。 'std :: forward(t)' – SoapBox

答えて

3

パーフェクト転送はパラメータの型が関数のテンプレートタイプなので、完璧な転送を実現する唯一の方法は、あなたの最初の例のようなものである場合にのみ機能します:

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

上記の作品ですのでTSomeType&またはSomeType&&と推測される特殊なケースです。

これはタプル要素の型情報が失われていることを意味するものではありません。それでも検索可能です(私はあなたがバリデーショナルのテンプレートパックをtypedefすることはできませんが)。たとえば、あなたはまだこのようなuse_args_types_for_something_elseを呼び出すことができます。

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

あり、しかし、何の良い一般的な解決策になるませんが、うまくいけば、このような状況はまれであるかもしれません。たとえば、この特定の例では、単にouterをオーバーロードするほうが簡単かもしれません。

+0

あなたの素敵で精巧な答えに感謝します。だから、C++ 11での完璧なフォワーディングに関しては、この奇妙なコンボ "template + rref + std :: forward"にあまり依存していないという気がします。これは、一般的な規則(「r値の参照のみがr値にバインドする」のような)がもう適用されない小さな点を作成します。完璧な転送のための特別な構文がC++ 11の方がうまくいかなかったのだろうかと思います。とにかく、この場合の回避策は、外側の2つの過負荷、const refとPFをエミュレートするrrefの2つのオーバーロードを実行することが可能なので、これほど大きな問題ではないことは事実です。 –

関連する問題