9

これは私がやろうとしていることです:

// base case
void f() {}

template <typename T, typename... Ts>
void f() {
    // do something with T
    f<Ts...>();
}

int main() {
    f<int, float, char>();
    return 0;
}

コンパイルされません:

prog.cpp: In instantiation of ‘void f() [with T = char; Ts = {}]’:
prog.cpp:6:5:   recursively required from ‘void f() [with T = float; Ts = {char}]’
prog.cpp:6:5:   required from ‘void f() [with T = int; Ts = {float, char}]’
prog.cpp:10:25:   required from here
prog.cpp:6:5: error: no matching function for call to ‘f()’
prog.cpp:6:5: note: candidate is:
prog.cpp:4:6: note: template<class T, class ... Ts> void f()
prog.cpp:4:6: note:   template argument deduction/substitution failed:
prog.cpp:6:5: note:   couldn't deduce template parameter ‘T’

このスレッドはこれを修正する方法を示していますが、基本ケースはテンプレートでなければなりません。私が理解している限り、T で動作するコードを複製する必要があるため、あまり好きではありません。それを回避する方法はありますか?

これまでのところ、2 つの解決策を思い付きました ( http://ideone.com/nPqU0l ):

template <typename...> struct types_helper {};

// base case
void f(types_helper<>) {}

template <typename T, typename... Ts>
void f(types_helper<T, Ts...>) {
    // do something with T
    f(types_helper<Ts...>());
}

int main() {
    f(types_helper<int, float, char>());
    return 0;
}

http://ideone.com/yyg6y9 :

#include <type_traits>

struct end_of_list;

template <typename T>
void f() {
    static_assert(std::is_same<T, end_of_list>::value, "error");
}

template <typename T1, typename T2, typename... Ts>
void f() {
    // do something with T
    f<T2, Ts...>();
}

int main() {
    f<int, float, char, end_of_list>();
    return 0;
}

これを行うためのより良い方法があるかどうか疑問に思います。

4

3 に答える 3

13

もう 1 つの方法は、非テンプレート関数fを、0 個以上のテンプレート引数を受け入れる可変個引数テンプレート関数に変換することです (もうf1 つは、1 つ以上のテンプレート引数を必要とします)。次に、あいまいさを避けるために、引数の数がゼロでない場合、SFINAE はこのテンプレート関数を取り除きます。コードは 1000 語よりも優れています。

#include <type_traits>

template <typename... Ts>
typename std::enable_if<sizeof...(Ts) == 0>::type f() {
}

template <typename T, typename... Ts>
void f() {
    // do something with T
    f<Ts...>();
}
于 2013-05-26T17:25:55.147 に答える