Template Comparison - D Programming Language

Menu

- Learn
- Documentation
  - Language Reference
  - Library Reference
  - Command-line Reference
  - Feature Overview
  - Articles
- Downloads
- Packages
- Community
  - Blog
  - Orgs using D
  - Twitter
  - Calendar
  - Forums
  - IRC
  - Community Discord
  - Wiki
  - GitHub
  - Issues
  - Get involved
  - Contributors
  - Foundation
  - Security Team
  - Donate
  - Sponsors
- Resources
  - Tour
  - Books
  - Tutorials
  - Tools
  - Editors
  - IDEs
  - run.dlang.io
  - Visual D
  - Acknowledgments
  - D Style
  - Glossary
  - Sitemap

Search
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;
    };

Copyright © 1999-2023 by the D Language Foundation | Page generated by Ddoc on Sun Jan 1 02:20:44 2023