2016-11-10 6 views
3

std :: applyを使用して可変長関数をタプルに適用できますか?例えばstd :: applyで可変長関数を適用する

、次のコードでは、GCC 6.2.1で正常に動作します:

void print_t(std::string i, std::string j) { 
    std::cout << i << " " << j << std::endl; 
} 

int main() { 
     std::tuple<std::string, std::string> t{"ab", "cd"}; 
     std::experimental::apply(print_t, t); 
     return 0; 
} 

しかし、私は可変引数関数に適用しようとした場合:

template<typename T> 
void vprint(T && t) { 
    std::cout << std::forward<T>(t) << std::endl; 
} 

template<typename T, typename ... Ts> 
void vprint(T && t, Ts ... ts) { 
    std::cout << std::forward<T>(t) << " "; 
    vprint<Ts...>(std::forward<Ts>(ts)...); 
} 

int main() { 
     std::tuple<std::string, std::string> t{"fd", "ab"}; 
     std::experimental::apply(vprint, t); 
     return 0; 
} 

をコンパイラは、テンプレートを推測することができないと文句を言い引数はvprintです。さて、明示的に書いてみましょう:

std::experimental::apply(vprint<std::string, std::string>, t); 

コンパイラは、標準ライブラリ内部を公開するいくつかのあいまいなエラーで終わります。

私はstd::applyの独自の実装をC++ 11で書いています。なぜ私はvariadic関数テンプレートの引数を推論できないのか理解しています。しかし、の理論ではstd::applyにはその控除に必要なすべての情報があります。

GCC6ではまだ実装されていない可変機能のアプリケーションですか? C++の17互換コンパイラはこのようなアプリケーションを許可しますか? そうでなければ、vprint<std::string, std::string>のようなインスタンス化された可変的なテンプレート関数のアプリケーションを許可しますか?

vprint<std::string, std::string>

答えて

6

、あなたがそう

std::experimental::apply(vprint<std::string, std::string>, std::move(t)); 

良い方法はファンクタ(ジェネリックラムダのおかげで)を使用することで、R値の参照を渡す必要があります。

std::experimental::apply([](auto&&... args) { 
          vprint(std::forward<decltype(args)>(args)...); 
         }, 
         t); 
+0

なぜ第二の変形が良いですか? 'std :: move'は基本的にrvalue参照へのキャストです。したがって、両方のコードスニペットのセマンティクスは同じようです。 – Sergey

+0

@Sergey:2番目の引数は引き続き引数を引き継ぎますが、最初の引数はタプルの型を知り、 't'を修正することができます(' print_t'はコピーによって渡されます)。 – Jarod42

+2

@Sergey 'print_t'は呼び出したい唯一の関数ではないと仮定します。 'std :: string &&'パラメータは自由に移動できます。あなたの実装では、それから移動することはありません。意味的には、 'std :: string'を移動した後は誰も関数呼び出しに頼らざるを得ませんが、' get'のように強い保証はできません。 – Yakk

関連する問題