可変個引数テンプレート

# 可変個引数テンプレート

最近使っていないけど、ちょっと入用があり、サンプルコードを書き始めたのが運の尽き。

## まず、書いてみる

### Sample1
```cpp
#include <iostream>
using namespace std;

void x() {
    cout << "end" << endl;
}

template <typename ...Args> void x(const char* n, Args&& ...args) {
    cout << __PRETTY_FUNCTION__ << endl;
    cout << "const char*: " << n << endl;
    x(args...);
}

template <typename ...Args> void x(int n, Args&& ...args) {
    cout << __PRETTY_FUNCTION__ << endl;
    cout << "int: " << n << endl;
    x(args...);
}

int main(void){
    x(123, "abc");
    x("abc", 123);
}
```

これだと、 ```x("abc", 123);```でエラーになる。具体的にはこんなエラー。

```
error: call to function 'x' that is neither visible in the template definition nor found by argument-dependent lookup
```

グーグル先生の翻訳によると

```
テンプレート定義に表示されておらず、引数依存のルックアップでも検出されない関数 'x'の呼び出し
```

正直しょ〜もないミスだったんだけど、関数のオーバーロードを使っているので、気付くまで4時間ほど遠回りをしてしまったので、反省を含めて。


## 第２形態

とりあえず、x() の第一引数を受け取る際も T でやってみようかということで実装。

### Sample2
```cpp
#include <iostream>
using namespace std;

void xx(int n) {
    cout << "int: " << n << endl;
}

void xx(const char* n) {
    cout << "const char*: " << n << endl;
}

void x() {
    cout << "end" << endl;
}

template <typename T, typename ...Args> void x(T&& n, Args&& ...args) {
    cout << __PRETTY_FUNCTION__ << endl;
    xx(n);
    x(args...);
}

int main(void){
    x(123, "abc");
    x("abc", 123);
}
```

これは、お行儀よく動く。


## ここから数時間悩む

もう、訳分からず、「&&か?」とか「std::fowardか？」とか、脳内の使用頻度が低い引き出しを整理したりして数時間。。。
こういう時は、ストラップトラップ氏の「プログラミング言語C++」を読む。そして、「§28.6.2 技術的詳細」のたかだか２ページを理解するのに数時間。。。
分かってしまえば、大したことないけど、テンパると２ページを日本語として認識するまで１０回以上繰り返し読むという始末。。。
結論、ここには答えはなく、ふと思いつき Sample1 ちょっと変えてみる。

## 第３形態

Sample1との違いは、 x(const char* n,...) と x(int n,...) を入れ替えただけ。

### Sample3

```cpp
#include <iostream>
using namespace std;

void x() {
    cout << "end" << endl;
}

template <typename ...Args> void x(int n, Args&& ...args) {
    cout << __PRETTY_FUNCTION__ << endl;
    cout << "int: " << n << endl;
    x(args...);
}

template <typename ...Args> void x(const char* n, Args&& ...args) {
    cout << __PRETTY_FUNCTION__ << endl;
    cout << "const char*: " << n << endl;
    x(args...);
}

int main(void){
    x(123, "abc");
    x("abc", 123);
}
```

すると、```x(123, "abc")```がエラーになる。
これで、後方の宣言を参照しているのが原因と気付く。


## 第４形態

ということで、関数をクラスメソッドにして前方宣言の省略して、これでやりたいことはできた。

### Sample4

```cpp
#include <iostream>
using namespace std;

struct X {
    static void x() {
        cout << "end" << endl;
    }
    
    template <typename ...Args> static void x(const char* n, Args&& ...args) {
        cout << __PRETTY_FUNCTION__ << endl;
        cout << "const char*: " << n << endl;
        x(args...);
    }
    
    template <typename ...Args> static void x(int n, Args&& ...args) {
        cout << __PRETTY_FUNCTION__ << endl;
        cout << "int: " << n << endl;
        x(args...);
    }
};

int main(void){
    X::x("abc", 123);
    X::x(123, "abc");
}
```


## 戒め

template は具象化されて使用されるため、プリプロセッサ的に展開されると思っちゃダメ。というか、単なる凡ミスか。。。orz


## ところで。。。

ネットでは、 T&& を Universal Reference だと解説してるサイトがあるけど、この Universal Reference は C++ の仕様では存在しない点に留意した方が良いと思われる。
Universal Reference を解説しているサイトでは、 template の文脈で現れる T&& のことを言っているようだけど、これは C++ の参照崩壊（Reference collapse）をtemplateで使用した一例を切り出して名称を与えているだけであり、仕様を正しく理解するためには参照崩壊を知る必要がある。というか、参照崩壊の仕様を見たほうが、実は話が早かったりする。
（参照崩壊につき -> https://en.cppreference.com/w/cpp/language/reference ）