The compiler can often infer a template type from the argument passed to a function.

type deduction When a call passes an `int`, `std::string`, or another value, the compiler can choose the matching `T`.

Template Type Deduction

example
template_type_deduction.cpp
Replay: real traced execution (multi-file project)
#include <iostream>
#include <string>
#include <type_traits>

template <typename T>
std::string typeName(T value) {
    if constexpr (std::is_same_v<T, int>) {
        return "int";
    } else if constexpr (std::is_same_v<T, std::string>) {
        return "string";
    } else {
        return "other";
    }
}

int main() {
    int attempts = 3;
    std::string word = "trace";

    std::cout << "attemptType=" << typeName(attempts) << std::endl;
    std::cout << "wordType=" << typeName(word) << std::endl;
    std::cout << "word=" << word << std::endl;
    return 0;
}
#include <iostream>
#include <string>
#include <type_traits>

template <typename T>
std::string typeName(T value) {
    if constexpr (std::is_same_v<T, int>) {
        return "int";
    } else if constexpr (std::is_same_v<T, std::string>) {
        return "string";
    } else {
        return "other";
    }
}

int main() {
    int attempts = 1;
    std::string word = "trace";

    std::cout << "attemptType=" << typeName(attempts) << std::endl;
    std::cout << "wordType=" << typeName(word) << std::endl;
    std::cout << "word=" << word << std::endl;
    return 0;
}
#include <iostream>
#include <string>
#include <type_traits>

template <typename T>
std::string typeName(T value) {
    if constexpr (std::is_same_v<T, int>) {
        return "int";
    } else if constexpr (std::is_same_v<T, std::string>) {
        return "string";
    } else {
        return "other";
    }
}

int main() {
    int attempts = 5;
    std::string word = "trace";

    std::cout << "attemptType=" << typeName(attempts) << std::endl;
    std::cout << "wordType=" << typeName(word) << std::endl;
    std::cout << "word=" << word << std::endl;
    return 0;
}
#include <iostream>
#include <string>
#include <type_traits>

template <typename T>
std::string typeName(T value) {
    if constexpr (std::is_same_v<T, int>) {
        return "int";
    } else if constexpr (std::is_same_v<T, std::string>) {
        return "string";
    } else {
        return "other";
    }
}

int main() {
    int attempts = 3;
    std::string word = "generic";

    std::cout << "attemptType=" << typeName(attempts) << std::endl;
    std::cout << "wordType=" << typeName(word) << std::endl;
    std::cout << "word=" << word << std::endl;
    return 0;
}
#include <iostream>
#include <string>
#include <type_traits>

template <typename T>
std::string typeName(T value) {
    if constexpr (std::is_same_v<T, int>) {
        return "int";
    } else if constexpr (std::is_same_v<T, std::string>) {
        return "string";
    } else {
        return "other";
    }
}

int main() {
    int attempts = 3;
    std::string word = "deduce";

    std::cout << "attemptType=" << typeName(attempts) << std::endl;
    std::cout << "wordType=" << typeName(word) << std::endl;
    std::cout << "word=" << word << std::endl;
    return 0;
}
  1. attempts ← 3, word ← trace

    16int main() {17    int attempts→ 3 = 3; //@attempts=1, 518    std::string word→ trace = "trace"; //@word="generic", "deduce"1920    std::cout << "attemptType=" << typeName(attempts3) << std::endl;21    std::cout << "wordType=" << typeName(wordtrace) << std::endl;22    std::cout << "word=" << wordtrace << std::endl;23    return 0;24}
    outputattemptType=int
    wordType=string
    word=trace
  1. attempts ← 1, word ← trace

    16int main() {17    int attempts→ 1 = 1;18    std::string word→ trace = "trace";1920    std::cout << "attemptType=" << typeName(attempts1) << std::endl;21    std::cout << "wordType=" << typeName(wordtrace) << std::endl;22    std::cout << "word=" << wordtrace << std::endl;23    return 0;24}
    outputattemptType=int
    wordType=string
    word=trace
  1. attempts ← 5, word ← trace

    16int main() {17    int attempts→ 5 = 5;18    std::string word→ trace = "trace";1920    std::cout << "attemptType=" << typeName(attempts5) << std::endl;21    std::cout << "wordType=" << typeName(wordtrace) << std::endl;22    std::cout << "word=" << wordtrace << std::endl;23    return 0;24}
    outputattemptType=int
    wordType=string
    word=trace
  1. attempts ← 3, word ← generic

    16int main() {17    int attempts→ 3 = 3;18    std::string word→ generic = "generic";1920    std::cout << "attemptType=" << typeName(attempts3) << std::endl;21    std::cout << "wordType=" << typeName(wordgeneric) << std::endl;22    std::cout << "word=" << wordgeneric << std::endl;23    return 0;24}
    outputattemptType=int
    wordType=string
    word=generic
  1. attempts ← 3, word ← deduce

    16int main() {17    int attempts→ 3 = 3;18    std::string word→ deduce = "deduce";1920    std::cout << "attemptType=" << typeName(attempts3) << std::endl;21    std::cout << "wordType=" << typeName(worddeduce) << std::endl;22    std::cout << "word=" << worddeduce << std::endl;23    return 0;24}
    outputattemptType=int
    wordType=string
    word=deduce