Variadicテンプレート
-
30-09-2019 - |
質問
私はバリアードテンプレートを導入する多くのリンクを見てきました。しかし、このアプローチを実証する編集可能な例を見たことがありません。
誰かが私に、そのような編集可能な例を見つけることができるいくつかのリンクを私に提供できますか?
解決
Variadicテンプレートは、まだ公式にリリースされていないC ++ 0x標準の一部です。バージョン4.3以来GCCでサポートされていますが、コンパイラスイッチ-STD = C ++ 0xを追加することにより、C ++ 0xのサポートを有効にする必要があります。
他のヒント
可能な限り単純な例の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";
}
Variadicテンプレートは、主にジェネリックライブラリの著者をターゲットにするC ++ 0x機能です。 「ユーザーコード」でそれらを見ることは期待していません。たとえば、C ++ 0x標準ライブラリでは、多くの場所で使用されています:std :: function、std :: async、std :: reference_wrapper、std :: tuple、std :: packaged_task、...
例を挙げると、variadicテンプレートに関して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機能を示します。
- 削除された関数(RValuesのコンストラクターを無効にする)
- RValue References(コンストラクターへのRValue引数の検出、完全な転送)
- 経由で控除を入力します
decltype
- 標準のライブラリ関数テンプレート
declval
表現を構築する目的でオブジェクトを作成するdecltype
(GCCはまだこの機能テンプレートを提供していません。自分で書く必要があります) - Variadicテンプレート(任意の数のパラメーターを受け入れる)
Variadicメンバーのテンプレートの目的は、次のように言及されているオブジェクトに議論を転送することです ptr
. 。これは、Tが関数ポインタータイプまたは過負荷の関数コールオペレーターを備えたクラスタイプである場合に機能するはずです。
乾杯! s
Variadicテンプレートの非常に簡単な例:
さまざまな数の引数を取り、それらをすべて印刷する関数が必要だとします。例:
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.)パラメーターリストに表示されるEllipsis(...)で示されるパラメーターパック。
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.)パラメーターパックは受け入れます ゼロ以上 テンプレートargs。それで、 print(T t, Args... args)
受け入れます 1つ以上 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
ポイント#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 ++ 11の前に、パラメーターの固定カウントでのみテンプレートを作成できます。
1つのパラメーターを使用した関数のFIRTSテンプレート。
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> >