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 has continued to improve on it. The D programming language is the first to comprehensively reengineer templates based on the C++ experience.

Template Comparison Table
Feature D C++
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>
Class Templates Yes:
class Foo(T)
{
    T x;
}
Yes:
template<class T>
class Foo
{
    T x;
};
Function Templates Yes:
T foo(T)(T i)
{
    ...
}
Yes:
template<class T>
T foo(T i)
{
    ...
}
Member Templates Yes Yes
Constructor Templates Yes Yes
Parameterize any Declaration Yes, classes, functions, any alias, variables, any enum, etc. can be parameterized, such as this variable:
template Foo(T)
{
    static T* p;
}
C++98
No, only classes and functions
C++11
Added using type aliases:
template<class T>
using ptr = T*;
ptr<int> p;
C++14
Added constexpr constant:
template<class T>
constexpr T pi = T(3.1415926535897932385L);
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;
C++98
No
C++11
Yes:
template<class T, class U> class Foo { };
template<class T> using MyFoo = Foo<T, int>;
MyFoo<unsigned> f;
Sequence Constructors No, use a variadic parameter instead C++98
No
C++11
Yes:
template <class T>
class Foo {
    Foo(std::initializer_list<T>);
};

Foo<double> f = { 1.2, 3.0, 6.8 };
Concepts Yes: Constraints C++98
No
C++20
Yes: Constraints and Concepts
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 };
};
Conditional Compilation based on Template Arguments Yes:
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
No, but workarounds exist:
template<class T> void foo(T i)
{
  // Differentiate using a
  // Helper<bool> specialization
  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
Yes, but it's limited to block scope:
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); // error foo is undeclared
}

template<class T, int maxLength> class HashTable {
    // error cannot use 'if' outside of a function
    if constexpr (maxLength < 0xFFFE)
        using CellIdx = ushort;
    else
        using CellIdx = uint;
    CellIdx index;
};
Template Forward Declarations Not necessary Yes:
template<class T>
class Foo;
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);
Sort of, using a class' members:
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);
Deducing this parameter type Yes C++23
Yes
Compile time execution of functions Yes:
int factorial(int i)
{
    if (i == 0)
        return 1;
    else
        return i * factorial(i - 1);
}
pragma(msg, factorial(6));
C++98
No
C++11
Yes, but only for constexpr functions.
constexpr was highly restricted in C++11, but each subsequent standard has eased these restrictions.
Parameters D C++
Type Parameters Yes:
class Foo(T)
{
    T x;
}
Foo!(int) f;
Yes:
template<class T>
class Foo
{
    T x;
};
Foo<int> f;
Integral Parameters Yes:
void foo(int i)()
{
    int v = i;
}
Yes:
template<int i>
void foo()
{
    int v = i;
}
Pointer Parameters Yes, a pointer to object or function Yes, a pointer to object or function
Reference Parameters No, but an alias parameter can be used instead (see below). Yes:
template<double& D>
void foo()
{
    double y = D;
}
Pointer to Member Parameters No, D does not have pointers to members. It does have delegates however, which can be used as parameters Yes
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;
};
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
Floating Point Parameters Yes:
class Foo(double D)
{
    double x = D;
}
...
Foo!(1.6) F;
C++98
No
C++11
Yes:
template<float f>
void foo()
{
    int v = f;
}
String Parameters Yes:
void foo(string format)(int i)
{
    writefln(format, i);
}
...
foo!("i = %s")(3);
C++98
No
C++17
Only indirectly:
template <const char *str>
struct S {};

S<"Foo"> foo1; // error A string literal argument is still illegal
const char foo_str[] = "foo";
S<foo_str> foo2; // Literal types are allowed, including arrays.
Local Class Parameters Yes C++98
No
C++17
Yes
Local Variable Parameters Yes No
Parameter Default Values Yes:
class Foo(T = int)
{
    T x;
}
Yes:
template<class T = int>
class Foo
{
    T x;
};
Variadic Parameters Yes, Variadic Templates:
void print(A...)(A a)
{
    foreach(t; a)
        writeln(t);
}
C++98
No
C++11
Yes:
// Need a zero- or one-argument version
// to handle the final argument.
void print() {};

template <class Arg, class... Args>
void print(const Arg& arg, Args&&... args)
{
    writeln(arg);
    print(std::forward<Args>(args)...);
}
Note that the example above was improved somewhat in C++17 using Fold Expressions:
template <class Args...>
void print(Args...&& args)
{
    (writeln(std::forward<Args.>(args)), ...);
}
Specializations D C++
Explicit Specialization Yes:
class Foo(T : int)
{
    T x;
}
Yes:
template<>
class Foo<int>
{
    int x;
};
Partial Specialization Yes:
class Foo(T : T*, U)
{
    T x;
}
Yes:
template<class T, class U>
class Foo<T*, U>
{
    T x;
};
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> >
{
    ...
};
Can specializations exist without a primary template? Yes No
Other D C++
Exported Templates Yes, it falls out as a natural consequence of modules C++98
Yes, but was only support in compilers based on EDG's front end.
C++11
Was removed from the language due to a lack of support.
SFINAE (Substitution Failure Is Not An Error) No Yes
Parse Template Definition Bodies before Instantiation Yes Not required by the Standard, but some implementations do
Overloading Function Templates with Functions Yes:
void foo(T)(T t) { }
void foo(int i) { }
Yes:
template<class T>
void foo(T t) { }
void foo(int i) { }
Implicit Function Template Instantiation Yes Yes
Templates can be evaluated in scope of instantiation rather than definition Yes, Template Mixins No, but can be faked using macros
Can extract arguments of template instance Yes:
struct Bar(T1, T2) { }
alias BarInst = Bar!(int, float);

static if (is(BarInst : Template!Args, alias Template, Args...))
{
    pragma(msg, Args);  // (int, float)
}
See is expressions.
No
Parsing Idiosyncracies D C++
Context-Free Grammar Yes:
class Foo(int i)
{
    ...
}
Foo!(3 > 4) f;
No:
template<int i> class Foo
{
    ...
};
Foo<3 > 4> f; // error 
Distinguish template arguments from other operators Yes:
class Foo(T)
{
    ...
}
class Bar(int i)
{
    ...
}
Foo!(Bar!(1)) x1;
C++98
No:
template<class T> class Foo
{
    ...
};
template<int i> class Bar
{
    ...
};
Foo<Bar<1>> x1; // error 
Foo<Bar<1> > x2;

C++11
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 
    }
};
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 
};
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);
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>();
}
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;
};