Последнее обновление:2026-10-12
Выведение аргументов шаблона класса CTAD в C++17¶
Введение¶
Шаблонное метапрограммирование в C++ давно известно разработчикам: и новички, и опытные программисты могут писать с его помощью обобщённый код с типовыми параметрами. С появлением в C++17 выведения аргументов шаблона класса (CTAD) работа с шаблонами классов стала более наглядной и гибкой.
Весь код этого раздела также будет опубликован в сообществе.
Появление CTAD в C++17 приносит следующие преимущества:
Например, такой громоздкий код
мы можем записать просто как:
Или ещё пример:
можно упростить до:
Итак, давайте сегодня разберёмся с CTAD.
CTAD — полное название Class template argument deduction (CTAD), выведение аргументов шаблона класса: вы даёте компилятору руководство по выведению (deduction guide), и мы можем пользоваться этой возможностью.
Если его не задать, как в примере ниже:
#include <iostream>
template <typename T, typename U>
struct MyPair {
T first{};
U second{};
};
int main() {
MyPair<int, int> p1{1, 2};
MyPair p2{1, 2};
std::cout << p1.first << ", " << p1.second << std::endl;
std::cout << p2.first << ", " << p2.second << std::endl;
return 0;
}
для p2 мы получим ошибку:
no viable constructor or deduction guide for deduction of template arguments of 'MyPair'
Как же это исправить?
Достаточно добавить deduction guide, записав его следующим образом.
Выведение аргументов шаблона класса (CTAD) упрощает инстанцирование шаблонов классов, позволяя компилятору выводить шаблонные параметры из аргументов конструктора. До появления CTAD разработчики обязаны были явно указывать шаблонные параметры при инстанцировании. С CTAD такая явная спецификация стала необязательной, что делает код более читабельным и простым в сопровождении.
template <typename T>
class Add{
private:
T first;
T second;
public:
Add() = default;
Add(T first, T second): first_{first}, second_{second} {}
T result() const { return first + second; }
};
int main(){
Add one(1,2); // T被推导为int
Add two{1.245, 3.1415}; // T被推导为double
Add three = {0.24f, 0.34f}; // T被推导为float
}
В приведённом примере CTAD позволяет выводить тип T на основе аргументов конструктора, устраняя необходимость в явном указании типа.
Инициализация нестатических членов¶
Но есть сценарий, где CTAD не работает, — инициализация нестатических членов. Например, при использовании внешнего MyPair в классе Test его придётся записывать полностью.
template <typename T = int, typename U = int>
struct MyPair {
T first{};
U second{};
};
template <typename T, typename U>
MyPair(T, U) -> MyPair<T, U>;
class Test {
MyPair p4; // use of class template 'MyPair' requires template arguments; argument
// deduction not allowed in non-static class member
};
В приведённом примере мы определили шаблонный класс MyPair и применили в нём CTAD. Однако при попытке использовать MyPair в классе Test как нестатический член CTAD не сработает из-за контекста инициализации нестатического члена, что приведёт к ошибке компиляции. В таком случае мы обязаны явно указать шаблонные параметры MyPair.
Мы видим, что в контексте инициализации нестатических членов CTAD не может вывести шаблонные параметры. Поэтому, когда шаблон класса является нестатическим членом, разработчику необходимо явно указывать все шаблонные параметры. На это следует особо обращать внимание в реальной разработке, чтобы обеспечить корректность и сопровождаемость кода.
Похожие темы¶
- Атрибут [[nodiscard]] в C++17 | C++那些事
- std::string_view в C++17 | C++那些事
- PMR-ресурсы памяти в C++17 | C++那些事
- Семнадцать расширенных возможностей C++17 | C++那些事
- C++17 optional_ref | C++那些事
- std::variant в C++17 | C++那些事
- Структурированные привязки в C++17 | C++那些事
- Выведение auto в шаблонах C++17 | C++那些事
- Шаблоны переменных в C++17 | C++那些事