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 No Yes
Parameterize any Declaration Yes, classes, functions, typedefs, variables, enums, etc. can be parameterized, such as this variable:
template Foo(T)
{
    static T* p;
}
C++98
No, only classes and functions
C++11
Yes:
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 C++98
No
C++11
Yes:
template <class T>
class Foo {
    Foo(std::initializer_list);
};

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:
template 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 specialization
  Helper>::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 is limited to block scope:
template<class T> void foo(T i)
{
  if constexpr (can_fast_foo)
    FastFoo foo = fast_foo(i);
  else
    SlowFoo foo = slow_foo(i);
  use_foo(foo); // error
}

template<class T, int maxLength> class HashTable {
    // error
    if constexpr (maxLength < 0xFFFE)
        using CellIdx = ushort;
    else
        using CellIdx = uint;
    CellIdx index;
};
Template Declarations (with no definition) No 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::bar b;
return Foo::foo('c', 3);
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);
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, D does not have a general reference type 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(char[] format)(int i)
{
    writefln(format, i);
}
...
foo!("i = %s")(3);
C++98
No
C++17
Only indirectly:
template <const char*>
struct S {};

S<"Foo"> foo1; error
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 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) { }
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:
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
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;
};