可変個引数テンプレートを紹介するリンクをたくさん見てきました。しかし、私はこのアプローチを示すコンパイル可能な例を見たことがありません。
誰かがそのようなコンパイル可能な例を見つけることができるいくつかのリンクを私に提供できますか?
可変個引数テンプレートを紹介するリンクをたくさん見てきました。しかし、私はこのアプローチを示すコンパイル可能な例を見たことがありません。
誰かがそのようなコンパイル可能な例を見つけることができるいくつかのリンクを私に提供できますか?
考えられる最も単純な例の1つは、次の実装でmax
あり、型にテンプレート化されていません。
int maximum(int n)
{
return n;
}
template<typename... Args>
int maximum(int n, Args... args)
{
return max(n, maximum(args...));
}
printf
正規の実装は少しだけ複雑です。
void printf(const char *s)
{
while (*s)
{
if (*s == '%' && *(++s) != '%')
throw "invalid format string: missing arguments";
std::cout << *s++;
}
}
template<typename T, typename... Args>
void printf(const char* s, T value, Args... args)
{
while (*s)
{
if (*s == '%' && *(++s) != '%')
{
std::cout << value;
printf(s, args...); // call even when *s == 0 to detect extra arguments
return;
}
std::cout << *s++;
}
throw "extra arguments provided to printf";
}
可変個引数テンプレートは、主に汎用ライブラリの作成者を対象とするC++0x機能です。私はそれらが「ユーザーコード」に表示されることを期待していません。たとえば、C ++ 0x標準ライブラリでは、std :: function、std :: async、std :: reference_wrapper、std :: tuple、std :: packaged_task、..などの多くの場所で使用されています。
例を示すために、可変個引数テンプレートに関してreference_wrapperを実装する方法を示します。
template<class T>
class reference_wrapper
{
T *ptr;
public:
explicit reference_wrapper(T& thing) : ptr(&thing) {}
explicit reference_wrapper(T&& ) = delete;
operator T&() const {return *ptr;}
template<class... Args>
decltype( declval<T&>()(declval<Args>()...) )
operator()(Args&&... args) const
{
return (*ptr)(forward<Args>(args)...);
}
};
これは標準ドラフトに完全には準拠していませんが、ほとんど変更を加えることなくコンパイルできるはずです。複数のC++0x機能を示しています。
decltype
declval
式を作成する目的でオブジェクトを作成するための標準ライブラリ関数テンプレートdecltype
(GCCはまだこの関数テンプレートを提供していません。自分で作成する必要があります)可変個引数メンバーテンプレートの目的は、によって参照されるオブジェクトに引数を転送することptr
です。これは、Tが関数ポインタ型またはオーバーロードされた関数呼び出し演算子を持つクラス型である場合に機能するはずです。
乾杯!s
可変個引数テンプレートの非常に単純な例:
可変数の引数を取り、それらすべてを出力する関数が必要だとします。例:
print("Hello", 1, 3.14, 5L);
その機能を機能させるには、基本的に2つの機能が必要です。
1つ目は、可変数の引数を取る関数です。
template<typename T, typename... Args>
void print(T t, Args ...args){
std::cout << t << ", ";
print(args...);
}
いくつかの説明:
1.)パラメータリストに表示される省略記号(...)で示されるパラメータパック。
typename...Args
| | << Optional whitespace. Can have multiple whitespaces in between them
Args...args
つまり、これらはすべて同じです。
typename ...args
typename...args
typename ... args
したがって、そこにある空白の正しい位置について心配する必要はありません。ただし、ベストプラクティスとしてIMOを使用する必要があるのは最大で1つの空白です。
2.)パック拡張:パターンの後に省略記号が続きます。
print(args...); //expand when you wish to use them
3.)パラメータパックは0個以上のテンプレート引数を受け入れます。したがって、1つ以上の引数print(T t, Args... args)
を受け入れます。
これを理解すると、コールフローを次のように視覚化できます。
print("Hello", 1, 3.14, 5L);
に変換されます:
print(string, int, float, long);
これは
print(int, float, long);
これは
print(float, long); // say Level 2
これは
print(long); // say Level 1
これは
print(); // say Level 0
Point#3を注意深く実行した場合print(T t, Args... args)
、レベル0では呼び出しを処理できないことに気付いたはずです。
したがって、レベル> = 0で追いつくには、同じ名前の別の関数が必要です。
2つ目は、呼び出しスタックの最上位で呼び出しを取得する関数です。
レベル0でキャッチ:
void print(){}
または、レベル1でキャッチします。
template<typename T>
void print(T t){ std::cout << t;}
または、レベル2でキャッチします。
template<typename T, typename U>
void print(T t, U u){ std::cout << t << ", " << u;}
すぐ...
これらのいずれも機能します。これが、次にそのような関数やクラスを作成するときに役立つことを願っています。
これは、ブログに掲載した可変個引数テンプレートの例です:http: //thenewcpp.wordpress.com/2011/11/23/variadic-templates-part-1-2/
コンパイルします。これは、タイプのグループから最大のタイプを見つけることを示しています。
#include <type_traits>
template <typename... Args>
struct find_biggest;
//the biggest of one thing is that one thing
template <typename First>
struct find_biggest<First>
{
typedef First type;
};
//the biggest of everything in Args and First
template <typename First, typename... Args>
struct find_biggest<First, Args...>
{
typedef typename find_biggest<Args...>::type next;
typedef typename std::conditional
<
sizeof(First) >= sizeof(next),
First,
next
>::type type;
};
可変個引数テンプレートは、まだ正式にリリースされていないC++0x標準の一部です。これらはバージョン4.3以降gccでサポートされていますが、コンパイラスイッチ-std = c ++ 0xを追加して、C++0xのサポートを有効にする必要があります。
C ++ 11より前は、パラメーターの数が固定されている場合にのみテンプレートを作成できました。
1つのパラメーターを持つ関数のテンプレートを作成します。
2つのパラメーターを持つ関数の2番目のテンプレート。...すなわち
C ++ 11ではテンプレートを1つしか記述できないため、コンパイラーは必要な関数自体を生成します。
良い例 http://eli.thegreenplace.net/2014/variadic-templates-in-c/
別の構文:展開、例:
template<typename VAL, typename... KEYS>
class MyMaps
{
typedef std::tuple< std::map<KEYS,VAL>... > Maps;
}
したがって:
MyMaps<int,int,string>:Maps
現在は実際には:
std::tuple<std::map<int,int>,std::map<string,int> >