ムラサメ研究ブログ

主にゲームやプログラミングのログ

右辺値参照~完全転送まで100%理解するぞ! part7 可変引数テンプレート

前回の

    template<class T>
    void hoge(T&& x){
        std::forward<T>(x);
    }

universal referenceを使うことで、右辺値参照も左辺値参照もどちらも入ってくる

std::forwardを使うことで、右辺値参照の場合は ムーブコンストラクタ、左辺値参照の場合は コピーコンストラクタ が実行される

これでほぼ完ぺきだけど 完全転送と呼ぶには hoge(x,y,z…) と、可変引数に対応しなければいけません!

可変引数テンプレート

まずは可変引数テンプレートの説明

可変引数(printfのような va_list)のような書式で コンパイル時に展開される

#include<iostream>

using namespace std;

void bar( int i, string& s ){
    cout << i << s << endl;
};

template<class... T>
void hoge(T... t){
  bar(t...);
}

auto main() -> int
{ 
  hoge(1, string(" test") );
//  hoge(1);   // hoge(int) は宣言されていないので エラー

  return 1;
}

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

上記コードの template<class… T> で、0個以上の引数をもつものにヒットする bar(t…); で、tを展開したパラメーターを引数にもつ barを呼ぶ

barに必要なだけオーバーロードすればいい

あとはこれを universal reference と std::forwardを使い

#include<iostream>

using namespace std;

void bar( int i,  string s ){
    cout << i << s << endl;
};

template<class... T>
void hoge(T&&... t){
  bar(std::forward<T>(t)...);
}

auto main() -> int
{ 
string s("s");
  hoge(1, s );
  hoge(1, " test" );
//  hoge(1);   // hoge(int) は宣言されていないので エラー

  return 1;
}

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

これで、どんな引数でも完全転送が出来ました!

ま、ビットフィールド等 工夫しなければ完全転送できないパターンもあるようですが 一般的には これでOK