2017-05-18 6 views
1

私はこれに尋ねた。questionstd::variant。バリアントが保持する型がすべてstd::coutで印刷可能であることを考慮すると、訪問者を実装する簡単な方法はありますか?テンプレートはstd :: variantの訪問に使用できますか?

Hereたとえば、各タイプをカバーする複数のラムダがありますが、すべて同じことをします(std::stringを除く):std::cout << arg << ' ';。私の自己を繰り返さない方法はありますか?

std::visit(overloaded { 
      [](int arg) { std::cout << arg; }, 
      [](long arg) { std::cout << arg; }, 
      [](double arg) { std::cout << arg; } 
      // I removed the std::string case 
     }, v); // v is the std::variant 

、代わりに書き込み:

std::visit( [](auto arg) { std::cout << arg; }, v); 

か何かのように:

template<typename T> 
void printer(T arg) {std::cout << arg; } 
//....... 
std::visit(printer, v); 
+2

2番目のブロック(一般的なラムダを使用)は動作するはずです。テンプレートが単一の関数またはオブジェクトではないため、3番目のブロック(テンプレート関数付き)は機能しません。あなたは 'operator()'というテンプレートで独自の呼び出し可能コードを書くことができます: 'struct printer {template void operator {){T arg} {std :: cout << arg; }}; std :: visit(printer {}、v); '(これは、一般的なラムダとほぼ同じです)。 –

+6

質問に[tag:C++]タグを追加し続けると、理由があります。今から自分でやってください。 –

答えて

2

std::visit( [](auto&& arg) { std::cout << arg; }, v); 

をコピーする必要はありませんこれは(転送)参照によってargをとります。私はそれを転送する気にしない;私はそれが本当に価値または左辺値であれば気にしません。

訪問にはオブジェクトが必要であり、テンプレート関数は関数のオブジェクトではないため、テンプレート関数は機能しません。オーバーロードセット名をC++のオブジェクトとして(まだ)渡すことはできません。

overloadトリックは、主に異なる動作をディスパッチする場合に使用します。あなたが行うことができます

ことの一つは、我々が取得、その後

template<typename T> 
void printer(T arg) {std::cout << arg; } 

std::visit([](auto&&arg){printer(arg);}, v); 

または

#define RETURNS(...) \ 
    noexcept(noexcept(__VA_ARGS__)) \ 
    -> decltype(__VA_ARGS__) 

#define OVERLOADS_OF(...) \ 
    [](auto&&...args) \ 
    RETURNS(__VA_ARGS__(decltype(args)(args)...)) \ 
    { return __VA_ARGS__(decltype(args)(args)...); } 

です:で指定された関数のオーバーロード集合を表し、匿名のオブジェクトを作成します

template<typename T> 
void printer(T arg) {std::cout << arg; } 

std::visit(OVERLOADS_OF(printer), v); 

トークンはprinterです。

+0

あなたはラムダの本体を忘れてしまい、最初の宣言型の後に余分な ')'があります。 – 0x499602D2

関連する問題