英語版
このページの英語版を見る

テンプレート比較

C++はテンプレートとテンプレートメタプログラミングの先駆けであり、 それを改善し続けてきた。 プログラミング言語Dは、 C++の経験に基づいてテンプレートを総合的に再設計した

テンプレート比較表
機能 D C++
引数リストの区切り Foo!(int) のように、!( ) を使用する。
引数が単一の()()トークンの場合、括弧は省略できる。Foo!int
< > を使用する。Foo<int>
クラステンプレート はい:
class Foo(T)
{
    T x;
}
はい:
template<class T>
class Foo
{
    T x;
};
関数テンプレート はい:
T foo(T)(T i)
{
    ...
}
はい:
template<class T>
T foo(T i)
{
    ...
}
メンバーテンプレート はい はい
コンストラクタテンプレート はい はい
あらゆる宣言のパラメータ化 はい。クラス、関数、任意のエイリアス、 変数、任意の列挙型などを パラメータ化できる。 例えば、この変数:
template Foo(T)
{
    static T* p;
}
いいえ、クラスと関数のみ C++98
いいえ、クラスと関数のみ
C++11
using 型のエイリアスを追加:
template<class T>
using ptr = T*;
ptr<int> p;
C++14
constexpr 定数を追加した。
template<class T>
constexpr T pi = T(3.1415926535897932385L);
テンプレート型定義:テンプレートパラメータの一部にのみバインドするエイリアスを作成する はい:
class Foo(T, U) { }
template MyFoo(T)
{
    alias MyFoo = Foo!(T, int);
}
MyFoo!(uint) f;
C++98
いいえ
C++11
はい:
template<class T, class U> class Foo { };
template<class T> using MyFoo = Foo<T, int>;
MyFoo<unsigned> f;
シーケンスコンストラクタ いいえ、代わりに 可変長パラメータを使用する C++98
いいえ
C++11
はい:
template <class T>
class Foo {
    Foo(std::initializer_list<T>);
};

Foo<double> f = { 1.2, 3.0, 6.8 };
概念 はい:制約 C++98
いいえ
C++20
はい:制約と概念
再帰的テンプレート はい:
template factorial(int n)
{
    const factorial = n * factorial!(n-1);
}
template factorial(int n : 1)
{
    const factorial = 1;
}
はい:
template<int n> class factorial
{
  public:
    enum { result = n * factorial<n-1>::result };
};
template<> class factorial<1>
{
  public:
    enum { result = 1 };
};
テンプレート引数に基づく 条件付きコンパイル はい:
void foo(T)(T i)
{
  static if (can_fast_foo!(T))
    FastFoo f = fast_foo(i);
  else
    SlowFoo f = slow_foo(i);
  use_foo(f);
}
class HashTable(T, int maxLength)
{
    static if (maxLength < 0xFFFE)
        alias CellIdx = ushort;
    else
        alias CellIdx = uint;
    CellIdx index;
}
C++98
いいえ、ただし回避策あり:
template<class T> void foo(T i)
{
  // Helper<bool>の特殊化を
  // 使用して区別する
  Helper<can_fast_foo<T>>::use_foo(i);
};

template<class T, int maxLength> class HashTable {
    typedef typename std::conditional<
            maxLength < 0xFFFE, uint16_t, uint32_t>
        ::type CellIdx;
    CellIdx index;
};

C++17
はい、ただしブロックスコープに限定されます。
template<class T> void foo(T i)
{
  if constexpr (can_fast_foo<T>)
    FastFoo foo = fast_foo(i);
  else
    SlowFoo foo = slow_foo(i);
  use_foo(foo); // エラー fooは宣言されていない
}

template<class T, int maxLength> class HashTable {
    // エラー 関数外では'if'が使えない
    if constexpr (maxLength < 0xFFFE)
        using CellIdx = ushort;
    else
        using CellIdx = uint;
    CellIdx index;
};
テンプレートフォワード宣言 必要ない はい:
template<class T>
class Foo;
同じパラメータを持つテンプレートをグループ化する はい:
template Foo(T, U)
{
    class Bar { ... }
    T foo(T t, U u) { ... }
}
Foo!(int,long).Bar b;
return Foo!(char,int).foo('c',3);
ある程度可能。クラスのメンバーを使用して:
template<class T, class U>
class Foo {
    class Bar { ... };
    static T foo(T t, U u) { ... }
};
Foo<int, long>::bar b;
return Foo<char, int>::foo('c', 3);
this パラメータの型を推測する はい C++23
はい
関数のコンパイル時実行 はい:
int factorial(int i)
{
    if (i == 0)
        return 1;
    else
        return i * factorial(i - 1);
}
pragma(msg, factorial(6));
C++98
いいえ
C++11
はい、ただしconstexpr関数のみ。
C++11ではconstexprは厳しく制限されていたが、その後の各標準ではこれらの制限が緩和されている。
パラメータ D C++
型パラメータ はい:
class Foo(T)
{
    T x;
}
Foo!(int) f;
はい:
template<class T>
class Foo
{
    T x;
};
Foo<int> f;
整数パラメータ はい:
void foo(int i)()
{
    int v = i;
}
はい:
template<int i>
void foo()
{
    int v = i;
}
ポインタパラメータ はい、オブジェクトまたは関数へのポインタ はい、オブジェクトまたは関数へのポインタ
参照パラメータ いいえ。ただし、エイリアス・パラメータを代わりに使用できる(下記参照)。 はい:
template<double& D>
void foo()
{
    double y = D;
}
メンバパラメータへのポインタ いいえ、Dにはメンバーへのポインタはない。 しかし、 デリゲートはあり、これはパラメータとして使用できる はい
テンプレート テンプレート パラメータ はい:
class Foo(T, alias C)
{
    C!(T) x;
}
はい:
template<class T,
         template<class U> class C>
class Foo
{
    C<T> x;
};
エイリアスパラメータ はい、任意のシンボルをエイリアスとしてテンプレートに渡すことができる。
void bar(int);
void bar(double);
void foo(T, alias S)(T t)
{
    S(t);
}
// bar(double)を呼び出す
foo!(double, bar)(1);
いいえ
浮動小数点パラメータ はい:
class Foo(double D)
{
    double x = D;
}
...
Foo!(1.6) F;
C++98
いいえ
C++11
はい:
template<float f>
void foo()
{
    int v = f;
}
文字列パラメータ はい:
void foo(string format)(int i)
{
    writefln(format, i);
}
...
foo!("i = %s")(3);
C++98
いいえ
C++17
間接的にのみ:
template <const char *str>
struct S {};

S<"Foo"> foo1; // エラー 文字列リテラル引数は依然として不正である
const char foo_str[] = "foo";
S<foo_str> foo2; // リテラル型は許可されており、配列も含まれる。
ローカルクラスパラメータ はい C++98
いいえ
C++17
はい
ローカル変数パラメータ はい いいえ
パラメータのデフォルト値 はい:
class Foo(T = int)
{
    T x;
}
はい:
template<class T = int>
class Foo
{
    T x;
};
可変長パラメータ 可変長テンプレート:
void print(A...)(A a)
{
    foreach(t; a)
        writeln(t);
}
C++98
いいえ
C++11
はい:
// 最後の引数を処理するには、
// 引数ゼロまたは引数1のバージョンが必要だ。
void print() {};

template <class Arg, class... Args>
void print(const Arg& arg, Args&&... args)
{
    writeln(arg);
    print(std::forward<Args>(args)...);
}
上記の例は、 C++17でFold式を使用して多少改善されている ことに注意。
template <class Args...>
void print(Args...&& args)
{
    (writeln(std::forward<Args.>(args)), ...);
}
特殊化 D C++
明示的特化 はい:
class Foo(T : int)
{
    T x;
}
はい:
template<>
class Foo<int>
{
    int x;
};
部分特殊化 はい:
class Foo(T : T*, U)
{
    T x;
}
はい:
template<class T, class U>
class Foo<T*, U>
{
    T x;
};
複数のパラメータから派生する部分的な専門性 はい:
class Foo(T : Bar!(T, U), U)
{
    ...
}
はい:
template<class T, class U>
class Foo< Bar<T,U> >
{
    ...
};
主要テンプレートなしで専門分野は存在し得るか? はい いいえ
その他 D C++
エクスポートされたテンプレート はい、モジュールの自然な結果として除外される C++98
はい、ただしEDGのフロントエンドに基づくコンパイラでのみサポートされていた。
C++11
サポート不足により言語から削除された。
SFINAE(Substitution Failure Is Not An Error) いいえ はい
インスタンス化の前にテンプレート定義本体を解析する はい 標準では必須ではないが、実装によっては必要となる
関数テンプレートのオーバーロード はい:
void foo(T)(T t) { }
void foo(int i) { }
はい:
template<class T>
void foo(T t) { }
void foo(int i) { }
暗黙的な関数テンプレートのインスタンス化 はい はい
テンプレートは定義ではなくインスタンス化のスコープで評価できる はい、テンプレートミックスイン いいえ。ただし、マクロを使用して擬似的に実現可能
テンプレートインスタンスの引数を抽出できる はい:
struct Bar(T1, T2) { }
alias BarInst = Bar!(int, float);

static if (is(BarInst : Template!Args, alias Template, Args...))
{
    pragma(msg, Args);  // (int, float)
}
式を参照
いいえ
パーシングの特殊性 D C++
文脈自由文法 はい:
class Foo(int i)
{
    ...
}
Foo!(3 > 4) f;
いいえ:
template<int i> class Foo
{
    ...
};
Foo<3 > 4> f; // エラー 
テンプレート引数と他の演算子を区別する はい:
class Foo(T)
{
    ...
}
class Bar(int i)
{
    ...
}
Foo!(Bar!(1)) x1;
C++98
いいえ:
template<class T> class Foo
{
    ...
};
template<int i> class Bar
{
    ...
};
Foo<Bar<1>> x1; // エラー 
Foo<Bar<1> > x2;

C++11
右大括弧で部分的に修正済みN1757
テンプレートパラメータの再宣言 はい:
class Foo(T)
{
    int T;
    void foo()
    {
        int T;
    }
}
いいえ:
template<class T>
class Foo
{
    int T; // エラー 
    void foo()
    {
        int T; // エラー 
    }
};
依存するベースクラスの検索 はい:
class Foo(T)
{
    alias A = int;
}
class Bar(T) : Foo(T)
{
    A x;
}
いいえ:
template<class T>
class Foo
{
  public:
    typedef int A;
};
template<class T>
class Bar : Foo<T>
{
  public:
    A x; // エラー 
};
前方参照 はい:
int g(void *);

class Foo(T)
{
    int foo()
    {
        return g(1);
    }
}

int g(int i);
いいえ:
int g(void *);

template<class T>
class Foo
{
    int foo()
    {
        return g(1); // エラー 
    }
};

int g(int i);
ヒントなしで解析可能なメンバーテンプレート はい:
class Foo
{
    Foo bar!(int I)();
}
void abd(T)(T f)
{
    T f1 = f.bar!(3)();
}
いいえ:
class Foo
{
  public:
    template<int> Foo *bar();
};
template<class T> void abc(T *f)
{
    T *f1 = f->bar<3>(); // エラー 
    T *f2 = f->template bar<3>();
}
ヒントなしで解析可能な依存型メンバ はい:
class Foo(T)
{
    T.A* a1;
}
いいえ:
template<class T> class Foo
{
  public:
    T::A *a1; // エラー 
    typename T::A *a2;
};