テンプレートの比較
C++ がテンプレートとテンプレートメタプログラミングの先駆けとなり、 C++0x へと改善が進んでいます。 プログラミング言語 D は、 C++ での経験に基づいて、 テンプレートを完全に設計し直した最初の言語です。
機能 | D | C++98 | C++0x |
---|---|---|---|
引数の渡し方 | !( ) を使う: Foo!(int) | < > を使う: Foo<int> | 変更なし |
クラステンプレート | Yes:
class Foo(T)
{
T x;
}
|
Yes:
template<class T> class Foo { T x; }; |
変更なし |
関数テンプレート | Yes:
T foo(T)(T i) { ... } |
Yes:
template<class T> T foo(T i) { ... } |
変更なし |
メンバテンプレート | Yes | Yes | 変更なし |
コンストラクタテンプレート | No | Yes | 変更なし |
任意の宣言のパラメタ化 | Yes。クラス、関数、typedef、
変数、enum などがパラメタ化できます。
以下の例のように:
template Foo(T) { static T* p; } |
No。クラスと関数のみ | 変更なし |
typedefテンプレート: テンプレート引数を使った宣言への alias を作る | Yes:
class Foo(T, U) { } template MyFoo(T) { alias Foo!(T, int) MyFoo; } MyFoo!(uint) f; |
No | Yes:
template<class T, class U> class Foo { }; template<class T> using MyFoo = Foo<T, int>; MyFoo<unsigned> f; |
シーケンス・コンストラクタ | No | No | Yes:
Foo<double> f = { 1.2, 3, 6.8 }; |
Concept | No。しかし、同じ効果を static if と static asserts で実現できます。 | No | Yes: Concepts for C++0x N1849 |
再帰テンプレート | Yes:
template factorial(int n) { const factorial = n * factorial!(n-1); } template factorial(int n : 1) { const factorial = 1; } |
Yes:
template<int n> class factorial { public: enum { result = n * factorial<n-1>::result }; }; template<> class factorial<1> { public: enum { result = 1 }; }; |
変更なし |
テンプレート引数に基づく 条件コンパイル | Yes:
template factorial(int n) { static if (n == 1) const factorial = 1; else const factorial = n * factorial!(n-1); } |
No:
template<int n> class factorial
{
public:
enum
{
#if (n == 1) // error
result = 1;
#else
result =
n * factorial<n-1>::result
#endif
};
};
|
変更なし |
テンプレートの(定義なしの)宣言 | No | Yes:
template<class T> class Foo; |
変更なし |
同じ引数のテンプレートのグループ化 | Yes:
template Foo(T, U) { class Bar { ... } T foo(T t, U u) { ... } } Foo!(int,long).Bar b; return Foo!(char,int).foo('c',3); |
No。それぞれ分離して書きます:
template<class T, class U> class Foo_Bar { ... }; template<class T, class U> T Foo_foo(T t, U u) { ... }; Foo_Bar<int,long> b; return Foo_foo<char,int>('c',3); |
変更なし |
関数のコンパイル時実行 | Yes:
int factorial(int i) { if (i == 0) return 1; else return i * factorial(i - 1); } static f = factorial(6); |
No | パラメタでの名前付き定数式: Generalized Constant Expressions N1972 |
引数 | D | C++98 | C++0x |
型引数 | Yes:
class Foo(T) { T x; } Foo!(int) f; |
Yes:
template<class T> class Foo { T x; }; Foo<int> f; |
変更なし |
整数引数 | Yes:
void foo(int i)() { int v = i; } |
Yes:
template<int i> void foo() { int v = i; } |
変更なし |
ポインタ引数 | Yes。オブジェクトか関数へのポインタ | Yes。オブジェクトか関数へのポインタ | 変更なし |
参照引数 | No, D には参照型がありません | Yes:
template<double& D> void foo() { double y = D; } |
変更なし |
メンバポインタ引数 | No, D にはメンバへのポインタがありません。代わりに delegates があって、これは引数として使えます | Yes | 変更なし |
テンプレートテンプレート引数 | Yes:
class Foo(T, alias C) { C!(T) x; } |
Yes:
template<class T, template<class U> class C> class Foo { C<T> x; }; |
変更なし |
alias 引数 | Yes, 任意のシンボルをテンプレート引数にaliasとして渡すことが可能:
void bar(int); void bar(double); void foo(T, alias S)(T t) { S(t); } // bar(double) を呼ぶ foo!(double, bar)(1); |
No | 変更なし |
浮動小数点数引数 | Yes:
class Foo(double D) { double x = D; } ... Foo!(1.6) F; |
No | 変更なし |
文字列引数 | Yes:
void foo(char[] format)(int i) { writefln(format, i); } ... foo!("i = %s")(3); |
No | 変更なし |
ローカルクラス引数 | Yes | No | Issue N1945 |
ローカル変数引数 | Yes | No | 変更なし |
引数のデフォルト値 | Yes:
class Foo(T = int) { T x; } |
Yes:
template<class T = int> class Foo { T x; }; |
変更なし |
可変個引数 | Yes, Variadic Templates:
void print(A...)(A a) { foreach(t; a) writefln(t); } |
No | Variadic Templates N2080 |
特殊化 | D | C++98 | C++0x |
明示的特殊化 | Yes:
class Foo(T : int) { T x; } |
Yes:
template<> class Foo<int> { int x; }; |
変更なし |
部分特殊化 | Yes:
class Foo(T : T*, U)
{
T x;
}
|
Yes:
template<class T, class U> class Foo<T*, U> { T x; }; |
変更なし |
複数パラメタによる部分特殊化 | Yes:
class Foo(T : Bar!(T, U), U)
{
...
}
|
Yes:
template<class T, class U> class Foo< Bar<T,U> > { ... }; |
変更なし |
プライマリテンプレートなしの特殊化 | Yes | No | 変更なし |
その他 | D | C++98 | C++0x |
テンプレートのexport | Yes, モジュールを導入した自然な帰結です | Yes, ただしEDGのフロントエンドを使ったコンパイラのみ | 変更なし |
SFINAE (Substitution Failure Is Not An Error) | Yes | Yes | 変更なし |
インスタンス化の前のテンプレート定義本体の構文解析 | Yes | 標準では要求されていないが、いくつかの実装はそうなっている | 変更なし |
関数テンプレートと関数のオーバーロード | No, しかし、同等の効果が
明示的に特殊化したテンプレートで実現できます:
void foo(T)(T t) { } void foo(T:int)(int t) { } |
Yes:
template<class T> void foo(T i) { } void foo(int t) { } |
変更なし |
関数テンプレートの暗黙のインスタンス化 | Yes | Yes | 変更なし |
定義ではなくインスタンス化のスコープでの テンプレートの評価 | Yes, Mixins | No, マクロで真似をすることは可能 | 変更なし |
構文的な特徴 | D | C++98 | C++0x |
文脈自由文法 | Yes:
class Foo!(int i) { ... } Foo!(3 > 4) f; |
No:
template<int i> class Foo
{
...
};
Foo<3 > 4> f; // error
|
変更なし |
テンプレート引数と他の演算子の区別 | Yes:
class Foo!(T) { ... } class Bar!(int i) { ... } Foo!(Bar!(1)) x1; |
No:
template<class T> class Foo
{
...
};
template<int i> class Bar
{
...
};
Foo<Bar<1>> x1; // error
Foo<Bar<1> > x2;
|
Right Angle Brackets N1757 で部分的に改善 |
テンプレート引数の再宣言 | Yes:
class Foo(T) { int T; void foo() { int T; } } |
No:
template<class T> class Foo { int T; // error void foo() { int T; // error } }; |
変更なし |
基底クラスの依存型のlookup | Yes:
class Foo(T) { typedef int A; } class Bar(T) : Foo(T) { A x; } |
No:
template<class T>
class Foo
{
public:
typedef int A;
};
template<class T>
class Bar : Foo<T>
{
public:
A x; // error
};
|
変更なし |
前方参照 | Yes:
int g(void *); class Foo(T) { int foo() { return g(1); } } int g(int i); |
No:
int g(void *);
template<class T>
class Foo
{
int foo()
{
return g(1); // error
}
};
int g(int i);
|
変更なし |
ヒントなしでメンバテンプレートの構文解析可能 | Yes:
class Foo { Foo bar!(int I)(); } void abd(T)(T f) { T f1 = f.bar!(3)(); } |
No:
class Foo
{
public:
template<int> Foo *bar();
};
template<class T> void abc(T *f)
{
T *f1 = f->bar<3>(); // error
T *f2 = f->template bar<3>();
}
|
変更なし |
ヒントなしで依存メンバ型が構文解析可能 | Yes:
class Foo(T)
{
T.A* a1;
}
|
No:
template |
変更なし |