23

可変個引数テンプレートを紹介するリンクをたくさん見てきました。しかし、私はこのアプローチを示すコンパイル可能な例を見たことがありません。

誰かがそのようなコンパイル可能な例を見つけることができるいくつかのリンクを私に提供できますか?

4

8 に答える 8

28

考えられる最も単純な例の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";
}
于 2010-09-05T07:23:53.430 に答える
11

可変個引数テンプレートは、主に汎用ライブラリの作成者を対象とする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

于 2010-09-03T15:44:28.523 に答える
6

可変個引数テンプレートの非常に単純な例:

可変数の引数を取り、それらすべてを出力する関数が必要だとします。例:

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;}

すぐ...

これらのいずれも機能します。これが、次にそのような関数やクラスを作成するときに役立つことを願っています。

于 2017-12-28T07:14:58.703 に答える
4

これは、ブログに掲載した可変個引数テンプレートの例です: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;
};
于 2011-11-23T21:47:58.187 に答える
2

可変個引数テンプレートは、まだ正式にリリースされていないC++0x標準の一部です。これらはバージョン4.3以降gccでサポートされていますが、コンパイラスイッチ-std = c ++ 0xを追加して、C++0xのサポートを有効にする必要があります。

于 2010-09-03T11:26:14.723 に答える
0

C ++ 11より前は、パラメーターの数が固定されている場合にのみテンプレートを作成できました。

1つのパラメーターを持つ関数のテンプレートを作成します。

2つのパラメーターを持つ関数の2番目のテンプレート。...すなわち

C ++ 11ではテンプレートを1つしか記述できないため、コンパイラーは必要な関数自体を生成します。

良い例 http://eli.thegreenplace.net/2014/variadic-templates-in-c/

于 2015-05-19T08:18:19.423 に答える
0

別の構文:展開、例:

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> >
于 2017-06-14T07:43:36.163 に答える