typename în C++

Introduce un parametru de tip într-un șablon sau anunță compilatorul că un nume care depinde de șablon este un tip.

Sintaxă
template <typename T> ...
typename T::value_type x;   // spune că T::value_type este un tip

Ce face typename

Prima folosire: în lista de parametri a unui șablon, template <typename T>. Aici typename și class sunt complet echivalente (template <class T>); typename este preferat pentru că T poate fi și int, nu doar o clasă.

A doua folosire: în interiorul unui șablon, un nume ca T::value_type depinde de T, iar compilatorul nu știe dinainte dacă este un tip sau o valoare. Implicit presupune că este valoare; scrii typename T::value_type ca să spui că este tip.

Din C++20, typename poate lipsi în multe locuri unde e evident că e nevoie de un tip (de exemplu tipul returnat sau al parametrilor), dar rămâne necesar în declarațiile de variabile locale.

Exemple

Exemplul 1: Tipul elementelor unui container

Container::value_type este int pentru std::vector<int> și double pentru std::list<double>. Fără typename, declarația nu s-ar compila.

#include <list>
#include <print>
#include <vector>

template <typename Container>
auto suma(const Container& c) {
    typename Container::value_type total{};
    for (const auto& x : c) {
        total += x;
    }
    return total;
}

int main() {
    std::vector<int> bucati = {3, 5, 2};
    std::list<double> greutati = {1.5, 2.25, 0.75};
    std::println("Bucăți: {}", suma(bucati));
    std::println("Kilograme: {}", suma(greutati));
}

Rezultat

Bucăți: 10
Kilograme: 4.5

Exemplul 2: typename și class în lista de parametri

#include <print>

template <typename T>
T dublu(T x) { return x * 2; }

template <class T>  // identic cu typename
T triplu(T x) { return x * 3; }

int main() {
    std::println("{} {}", dublu(21), triplu(1.5));
}

Rezultat

42 4.5

Greșeli frecvente

  • Uiți typename înaintea unui tip dependent: Container::iterator it; într-un șablon. Eroarea este de tipul „missing ‘typename’ prior to dependent type name”.
  • Pui typename în fața unui nume care nu depinde de un parametru de șablon (de exemplu typename std::vector<int>::iterator în afara unui șablon). În cod obișnuit nu este necesar.

Comenzi înrudite

  • template: Scrie o funcție sau o clasă o singură dată, pentru orice tip; compilatorul generează varianta potrivită pentru fiecare tip folosit.
  • using: Aduce nume dintr-un spațiu de nume în locul curent sau creează un nume nou (alias) pentru un tip existent.
  • concept: Dă un nume unui set de cerințe pentru tipuri, folosit ca să restrângi ce tipuri acceptă un șablon.