C++ 17 – Class Template Argument Deduction (CTAD)

When you want to create an object for a template class, you would inform the compiler about the data types of the template arguments. From C++ 17 onwards, we are no longer required to specify the data types due to the CTAD feature – Class Template Argument Deduction.

Let us say you want an object display out of a template class Display, and the type parameters are int and float. You would use the code below before C++ 17.

Display<int, float> display(1, 2.1);

But from C++ 17 onwards, it is much simple. You only need to specify as below—no need to inform about the data types.

Display display(1, 2.1);

The compiler would automatically deduce what the argument types are. That is why it is called Class Template Argument Deduction.

Let us see this simple concept using an example C++ program. We will examine the results of compilation and execution with C++ 14 and C++ 17. The complete program is available for download at https://github.com/codeversionmaster/cplusplus/blob/cplusplus17/ctad.cpp.

The machine used was Ubuntu 22.04 machine with g++ installed. Use the below command to find the version the C++ version supported.

$ echo | g++ -dM -E -x c++ - | grep cplusplus
#define __cplusplus 201703L

The complete program is as below.

#include <iostream>
using namespace std;

template <class T, class U>
class Display {
    T first;
    U second;


        Display(T arg1, U arg2):first(arg1),second(arg2) {}

        void print() {
            cout << "first = " << first << " second = " << second << "\n";

int main()
    //Display<int, float> display(1, 2.1); //Prior to C++ 17
    Display display(1, 2.1);  //From C++ 17

The first portion of the code is where a class Display with two member variables (first and second) is declared. It is a template class accepting two template data types – and U. The constructor Display takes two arguments of data type as given by and U. The member variables, first and second, are assigned these arguments. There is another function print that prints the member variables.

Consider the function main where the template class Display is initialized to create an object with a name display and calls the constructor function with two arguments. We have uncommented the statement that corresponds to C++ 17 support. The data types are not specified here.

    //Display<int, float> display(1, 2.1); //Prior to C++ 17
    Display display(1, 2.1);  //From C++ 17

Let us compile this with -std=c++14 to consider the program as C++ 14 program. The compiler throws the error – missing template arguments before ‘display’.

$ g++ -std=c++14 ctad.cpp -o ctad
ctad.cpp: In function ‘int main()’:
ctad.cpp:23:13: error: missing template arguments before ‘display’
   23 |     Display display(1, 2.1);  //From C++ 17
      |             ^~~~~~~
ctad.cpp:24:5: error: ‘display’ was not declared in this scope; did you mean ‘Display’?
   24 |     display.print();
      |     ^~~~~~~
      |     Display

Now, if we compile it considering it as C++ 17 program, it compiles and executes well.

$ g++ -std=c++17 ctad.cpp -o ctad
$ ./ctad
first = 1 second = 2.1

Now let us comment the C++ 17 supported statement and uncomment the previous line to pass the template arguments.

    Display<int, float> display(1, 2.1); //Prior to C++ 17
    //Display display(1, 2.1);  //From C++ 17

Now, let us compile the program using C++ 14 support. You can see that it compiles and executes well.

$ g++ -std=c++14 ctad.cpp -o ctad
$ ./ctad
first = 1 second = 2.1

We saw on a real system with a real example that C++ 17 program can have template class instantiation without the template argument data types specified.

Below are some of the advantages of the CTAD feature.

  • High readability is achieved as we no longer need to specify the data types each time we instantiate a template class.
  •  It is easy to refactor the code as a lot of common code is removed across the program
  •  Cleaner error messages are seen now as the compiler tries to deduce the template argument data types.