LoginSignup
10
8

C言語でマクロで作成していた機能をtemplateで作るために、
可変長引数templateを勉強し始めました。

<この項は書きかけです。順次追記します。>

可変引数テンプレート1

のプログラムを入力して編纂(compile)してみます。

temp.cpp
#include <iostream>
#include <cstdlib>

template <class... Args>
struct X {
  // パラメータパックを ... で展開して、
  // std::tupleクラステンプレートの引数として渡す
  std::tuple<Args...> values;
};

void g(int, char, const std::string&) {}

template <class... Args>
void f(Args... args)
{
  // パラメータパックを ... で展開して、
  // 関数g()の引数として渡す
  g(args...);
}

int main (){
f(3, 'a', "hello");
return EXIT_SUCCESS;
}

Xcodeのclang++でコンパイルするとエラーが出た。

$ clang++ temp.cpp
temp.cpp:4:16: warning: variadic templates are a C++11 extension
      [-Wc++11-extensions]
template <class... Args>
               ^
temp.cpp:8:8: error: no type named 'tuple' in namespace 'std'
  std::tuple<Args...> values;
  ~~~~~^
temp.cpp:8:13: error: expected member name or ';' after declaration specifiers
  std::tuple<Args...> values;
  ~~~~~~~~~~^
temp.cpp:13:16: warning: variadic templates are a C++11 extension
      [-Wc++11-extensions]
template <class... Args>
               ^
2 warnings and 2 errors generated.

blew install llvm --with-clang で導入したclang++だとエラーが出なかった。

$ clang++ --version
clang version 6.0.0 (tags/RELEASE_600/final)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin
$ clang++ temp.cpp -std=c++2a
$ a.out
$ 

何も出力しないプログラムは嬉しくない。

tuple

tuple.cpp
#include <iostream>
#include <tuple>
#include <string>
#include <cstdlib>

using namespace std;

int main()
{
  // 3要素のタプルを作る
  tuple<int, char, std::string> t = std::make_tuple(1, 'a', "hello");

  // 0番目の要素を参照
  int& i = get<0>(t);
  cout << i << endl;

  // 2番目の要素を参照
  string& s = get<2>(t);
  cout << s << endl;

  return EXIT_SUCCESS;
}

Xcodeのclang++でコンパイルするとエラーが出た。

$ clang++ tuple.cpp
tuple.cpp:11:3: error: use of undeclared identifier 'tuple'
  tuple<int, char, std::string> t = std::make_tuple(1, 'a', "hello");
  ^
tuple.cpp:11:12: error: expected
      '(' for function-style cast or type construction
  tuple<int, char, std::string> t = std::make_tuple(1, 'a', "hello");
        ~~~^
tuple.cpp:14:19: error: use of undeclared identifier 't'
  int& i = get<0>(t);
                  ^
tuple.cpp:18:22: error: use of undeclared identifier 't'
  string& s = get<2>(t);
                     ^
4 errors generated.

blew install llvm --with-clangで導入したclang++だとエラーが出なかった。

$ clang++ tuple.cpp
$ ./a.out
1
hello

出力があると確認しやすい。

可変引数テンプレート2

https://cpprefjp.github.io/lang/cpp11/variadic_templates.html
の2つめのプログラム。
using namespace std;などを追加。

temp2.cpp
#include <iostream>
#include <utility>
#include <cstdlib>

using namespace std;

// パラメータパックが空になったら終了
void print() {}

// ひとつ以上のパラメータを受け取るようにし、
// 可変引数を先頭とそれ以外に分割する
template <class Head, class... Tail>
void print(Head&& head, Tail&&... tail)
{
  cout << head << endl;

  // パラメータパックtailをさらにheadとtailに分割する
  print(move(tail)...);
}

int main()
{
  print(1, 'a', "hello");
  return EXIT_SUCCESS;
}
$ clang++ temp2.cpp
$ ./a.out
1
a
hello

可変引数テンプレート関数

amowwee.cpp
#include <iostream>
#include <tuple>
#include <string>
#include <cstdlib>

using namespace std;

template <class... Args>
void func(Args... args)
{
    // sizeof...で可変引数にいくつ変数を持っているか調べる
    std::cout << sizeof...(args) << std::endl;
    // argsはそのままでは使えない
    // std::cout << args << std::endl;    // compile error
}

int main()
{
    func("foo", "bar", "hoge", "huga");    // 4
    func();    // 0, ...Argsは引数無しでもOK
    return EXIT_SUCCESS;
}

Xcodeのclang++では警告が出た。

$ clang++ amowwee.cpp 
amowwee.cpp:8:16: warning: variadic templates are a C++11 extension
      [-Wc++11-extensions]
template <class... Args>
               ^
1 warning generated.
$ ./a.out
4
0

blew install llvm --with-clangで導入した方は警告もない。

clang++ amowwee.cpp -Wall
$ ./a.out
4
0

vc++でも全部コンパイルしてみた。/EHscのコンパイルスイッチをつければ警告なし。実行結果は同じ。

被引用算譜(referenced program)

MISRA C++ 5-0-16
https://qiita.com/kaizen_nagoya/items/7df2d4e05db724752a74

参考文献(reference)

LLVMソースコードのコンパイルをしようと思ってハマった罠とそこから脱出するための努力
https://qiita.com/kaizen_nagoya/items/16f270e42b947756ced3

可変長template引数でネスト機能付きタスクリストを作る
https://qiita.com/unsolvedprobrem/items/a77f3e9a856af2f83ba3

C++のパラメータパック基礎&パック展開テクニック
https://qiita.com/_EnumHack/items/677363eec054d70b298d

可変長テンプレート引数のそれぞれの値に関数を適用する
https://qiita.com/janus_wel/items/de793bcd2aa845e3e8cc
<この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。>

文書履歴(document history)

ver. 0.10 初稿 20180806 午前
ver. 0.11 brew install llvm --with-clangで導入したコンパイラの結果追記 20180806 午後
ver. 0.12 被参照算譜追記 20180807
ver. 0.13 using namespace std;追記 20180808
ver. 0.14 vc++で動作確認 20180809
ver. 0.15 表題変更 20190104

最後までおよみいただきありがとうございました。

いいね 💚、フォローをお願いします。

Thank you very much for reading to the last sentence.

Please press the like icon 💚 and follow me for your happy life.

10
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8