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

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

이 글의 핵심

CTAD lets you write `std::vector v = {1,2,3}` and custom types with constructor-driven template argument deduction.

Introduction

CTAD (Class Template Argument Deduction), introduced in C++17, deduces class template arguments from constructor arguments so you can omit explicit template parameters.


1. CTAD basics

C++14 vs C++17

// C++14: explicit types
std::pair<int, double> p(1, 3.14);
std::vector<int> vec = {1, 2, 3};

// C++17: deduced
std::pair p(1, 3.14);
std::vector vec = {1, 2, 3};

Standard library

#include <vector>
#include <map>
#include <tuple>
#include <array>

int main() {
    std::pair p(1, "Hello");
    std::tuple t(1, 2.0, "Hi");
    std::vector vec = {1, 2, 3};
    std::map m = {{"a", 1}, {"b", 2}};
}

2. Custom class CTAD

Basic example

template<typename T>
class Container {
    T value;
    
public:
    Container(T v) : value(v) {}
    
    T get() const { return value; }
};

int main() {
    Container c(42);
    Container c2(3.14);
    Container c3("Hello");
}

Copy construction

template<typename T>
class Wrapper {
    T value;
    
public:
    Wrapper(T v) : value(v) {}
    Wrapper(const Wrapper& other) : value(other.value) {}
    
    T get() const { return value; }
};

3. Deduction guides

Simple guide

template<typename T>
class MyClass {
    T value;
    
public:
    MyClass(T v) : value(v) {}
};

template<typename T>
MyClass(T) -> MyClass<T>;

Custom conversions

template<typename T>
class Container {
    T value;
    
public:
    Container(T v) : value(v) {}
    T get() const { return value; }
};

Container(const char*) -> Container<std::string>;

Iterator / nested types

Guides can map (It, It) to vector<value_type_t<It>>—the standard library does this for several constructors.


4. Common pitfalls

Ambiguous deduction

Multiple constructors can compete; guides disambiguate intent.

initializer_list and CTAD

Brace initialization can prefer initializer_list constructors—sometimes surprising; be explicit when needed.

const char* and std::string

Pairs of string literals may deduce to pair<string,string> if you construct that way explicitly; know your overload set.


5. Disabling deduction

explicit constructors do not participate in implicit copy-list-initialization patterns the same way—use explicit types when you must.


6. Examples: smart pointer–style, typed IDs

The article includes SmartPtr(T*) -> SmartPtr<T> and typed identifier wrappers—same code as the Korean version.


Summary

  1. CTAD deduces class template parameters from constructors (C++17).
  2. Deduction guides customize that mapping.
  3. Standard library types commonly use CTAD.
  4. Cost: compile-time only; no runtime overhead.

Trade-offs

ProsCons
Shorter codeTypes can be less visible at a glance
Still type-safeAmbiguity if overloads clash
Compile-timeRequires C++17+

Tips

  • Prefer CTAD when types are obvious.
  • Spell out template arguments when readability wins.
  • Use guides for conversions like const char*std::string.

  • Deduction guides
  • if constexpr
  • Template argument deduction

Keywords

C++, CTAD, class template argument deduction, deduction guide, C++17.