Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

Template Comparison

C++ pioneered templates and template metaprogramming, and continues to improve on it with C++0x. The D programming language is the first to comprehensively reengineer templates based on the C++ experience. Since C++0x is not a ratified standard yet, proposed changes to C++ are subject to change.

Template Comparison Table
Feature D C++98 C++0x
Argument list delineation Uses !( ), as in Foo!(int).
Can omit parens when the argument is a single lexical token: Foo!int
Uses < > as in Foo<int> No change
Class Templates Yes:
class Foo(T)
{
    T x;
}
Yes:
template<class T>
class Foo
{
    T x;
};
No change
Function Templates Yes:
T foo(T)(T i)
{
    ...
}
Yes:
template<class T>
T foo(T i)
{
    ...
}
No change
Member Templates Yes Yes No change
Constructor Templates No Yes No change
Parameterize any Declaration Yes, classes, functions, typedefs, variables, enums, etc. can be parameterized, such as this variable:
template Foo(T)
{
    static T* p;
}
No, only classes and functions No change
Template Typedefs: Create an alias that binds to some but not all of the template parameters Yes:
class Foo(T, U) { }
template MyFoo(T)
{
    alias MyFoo = Foo!(T, int);
}
MyFoo!(uint) f;
No Yes:
template<class T, class U> class Foo { };
template<class T> using MyFoo = Foo<T, int>;
MyFoo<unsigned> f;
Sequence Constructors No No Yes:
Foo<double> f = { 1.2, 3, 6.8 };
Concepts Yes: Constraints No Yes: Concepts for C++0x N1849
Recursive Templates 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 };
};
No change
Conditional Compilation based on Template Arguments 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 change
Template Declarations (with no definition) No Yes:
template<class T>
class Foo;
No change
Grouping templates with the same parameters together 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, each must be separate:
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);
No change
Compile time execution of functions Yes:
int factorial(int i)
{
    if (i == 0)
        return 1;
    else
        return i * factorial(i - 1);
}
static f = factorial(6);
No Named constant expressions with parameters: Generalized Constant Expressions N1972
Parameters D C++98 C++0x
Type Parameters Yes:
class Foo(T)
{
    T x;
}
Foo!(int) f;
Yes:
template<class T>
class Foo
{
    T x;
};
Foo<int> f;
No change
Integral Parameters Yes:
void foo(int i)()
{
    int v = i;
}
Yes:
template<int i>
void foo()
{
    int v = i;
}
No change
Pointer Parameters Yes, a pointer to object or function Yes, a pointer to object or function No change
Reference Parameters No, D does not have a general reference type Yes:
template<double& D>
void foo()
{
    double y = D;
}
No change
Pointer to Member Parameters No, D does not have pointers to members, it has delegates, which can be used as parameters Yes No change
Template Template Parameters Yes:
class Foo(T, alias C)
{
    C!(T) x;
}
Yes:
template<class T,
         template<class U> class C>
class Foo
{
    C<T> x;
};
No change
Alias Parameters Yes, any symbol can be passed to a template as an alias:
void bar(int);
void bar(double);
void foo(T, alias S)(T t)
{
    S(t);
}
// calls bar(double)
foo!(double, bar)(1);
No No change
Floating Point Parameters Yes:
class Foo(double D)
{
    double x = D;
}
...
Foo!(1.6) F;
No No change
String Parameters Yes:
void foo(char[] format)(int i)
{
    writefln(format, i);
}
...
foo!("i = %s")(3);
No No change
Local Class Parameters Yes No Issue N1945
Local Variable Parameters Yes No No change
Parameter Default Values Yes:
class Foo(T = int)
{
    T x;
}
Yes:
template<class T = int>
class Foo
{
    T x;
};
No change
Variadic Parameters Yes, Variadic Templates:
void print(A...)(A a)
{
    foreach(t; a)
        writeln(t);
}
No Variadic Templates N2080
Specializations D C++98 C++0x
Explicit Specialization Yes:
class Foo(T : int)
{
    T x;
}
Yes:
template<>
class Foo<int>
{
    int x;
};
No change
Partial Specialization Yes:
class Foo(T : T*, U)
{
    T x;
}
Yes:
template<class T, class U>
class Foo<T*, U>
{
    T x;
};
No change
Partial specialization derived from multiple parameters Yes:
class Foo(T : Bar!(T, U), U)
{
    ...
}
Yes:
template<class T, class U>
class Foo< Bar<T,U> >
{
    ...
};
No change
Can specializations exist without a primary template? Yes No No change
Other D C++98 C++0x
Exported Templates Yes, it falls out as a natural consequence of modules Yes, though only in compilers based on EDG's front end No change
SFINAE (Substitution Failure Is Not An Error) Yes Yes No change
Parse Template Definition Bodies before Instantiation Yes Not required by Standard, but some implementations do No change
Overloading Function Templates with Functions No, but the equivalent can be done with explicitly specialized templates:
void foo(T)(T t) { }
void foo(T:int)(int t) { }
Yes:
template<class T>
void foo(T i) { }

void foo(int t) { }
No change
Implicit Function Template Instantiation Yes Yes No change
Templates can be evaluated in scope of instantiation rather than definition Yes, Mixins No, but can be faked using macros No change
Can extract arguments of template instance Yes:
class Foo(T)
{
    static if (is(T x : T!A, A...))
    {
        pragma(msg, A);  // (int, float)
    }
}

struct Bar(T1, T2) { }
alias BarInst = Bar!(int, float);
Foo!(BarInst) f;
See is expressions.
No No change
Parsing Idiosyncracies D C++98 C++0x
Context-Free Grammar Yes:
class Foo(int i)
{
    ...
}
Foo!(3 > 4) f;
No:
template<int i> class Foo
{
    ...
};
Foo<3 > 4> f; // error
No change
Distinguish template arguments from other operators 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;
Partially fixed by Right Angle Brackets N1757
Redeclaration of Template Parameter Yes:
class Foo(T)
{
    int T;
    void foo()
    {
        int T;
    }
}
No:
template<class T>
class Foo
{
    int T; // error
    void foo()
    {
        int T; // error
    }
};
No change
Dependent Base Class Lookup Yes:
class Foo(T)
{
    alias A = int;
}
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
};
No change
Forward Referencing 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);
No change
Member templates parseable without hints 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>();
}
No change
Dependent type members parseable without hints Yes:
class Foo(T)
{
    T.A* a1;
}
No:
template<class T> class Foo
{
  public:
    T::A *a1; // error
    typename T::A *a2;
};
No change