Namespaces
Variants

Class template argument deduction (CTAD) (since C++17)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

クラステンプレートをインスタンス化するためには、 class template のすべてのテンプレート引数が既知である必要がありますが、すべてのテンプレート引数を明示的に指定する必要はありません。以下のコンテキストでは、コンパイラが初期化子の型からテンプレート引数を推論します:

  • 変数の初期化を指定する任意の 宣言 および変数テンプレート。その宣言された型がクラステンプレート( cv修飾 されている可能性あり)であるもの:
std::pair p(2, 4.5);     // std::pair<int, double> p(2, 4.5); と推論される
std::tuple t(4, 3, 2.5); // auto t = std::make_tuple(4, 3, 2.5); と同じ
std::less l;             // std::less<void> l; と同じ
template<class T>
struct A
{
    A(T, T);
};
auto y = new A{1, 2}; // 割り当てられた型は A<int>
auto lck = std::lock_guard(mtx);     // std::lock_guard<std::mutex> と推論される
std::copy_n(vi1, 3,
    std::back_insert_iterator(vi2)); // std::back_insert_iterator<T> と推論される
                                     // ここで T はコンテナ vi2 の型
std::for_each(vi.begin(), vi.end(),
    Foo([&](int i) {...}));          // Foo<T> と推論される
                                     // ここで T は一意のラムダ型
  • 定数テンプレートパラメータの型:
template<class T>
struct X
{
    constexpr X(T) {}
};
template<X x>
struct Y {};
Y<0> y; // OK, Y<X<int>(0)>
(C++20以降)

目次

クラステンプレートの推論

暗黙的に生成される推論ガイド

関数形式キャストまたは変数宣言において、型指定子がプライマリクラステンプレートの名前 C のみで構成されている場合(つまり、付随するテンプレート引数リストがない場合)、推論の候補は以下のように形成されます:

  • C が定義されている場合、名前付きプライマリテンプレートで宣言されている各コンストラクタ(またはコンストラクタテンプレート) C i に対して、以下のすべての条件を満たす架空の関数テンプレート F i が構築されます:
  • F i のテンプレートパラメータは、 C のテンプレートパラメータに続き(もし C i がコンストラクタテンプレートである場合)、 C i のテンプレートパラメータが追加されます (デフォルトテンプレート引数も含まれます)。
  • F i 関連制約 は、 C の関連制約と C i の関連制約の論理積である。
(C++20以降)
  • F i パラメータリスト は、 C i のパラメータリストです。
  • F i の戻り値の型は、 C にクラステンプレートのテンプレートパラメータを <> で囲んで続けたものです。
  • C が定義されていないか、いずれのコンストラクタも宣言していない場合、仮想的なコンストラクタ C() から上記と同様に導出された追加の架空の関数テンプレートが追加されます。
  • いずれの場合でも、仮想的なコンストラクタ C(C) から上記のように導出された追加の架空の関数テンプレートが追加され、これはコピー推論候補と呼ばれます。
  • ユーザー定義deduction guide G i に対して、以下の全ての条件を満たす仮想的な関数または関数テンプレート F i が構築されます:
  • F i のパラメータリストは、 G i のパラメータリストである。
  • F i の戻り値型は、 G i の単純なテンプレート識別子である。
  • G i がテンプレートパラメータを持つ場合(構文 (2) )、 F i は関数テンプレートであり、そのテンプレートパラメータリストは G i のテンプレートパラメータリストである。そうでない場合、 F i は関数である。
  • さらに、以下の条件がすべて満たされる場合:
  • C が定義され、依存する基底クラスが仮想関数や仮想基底クラスを持たないと仮定した場合に 集成体型 の要件を満たす場合、
  • C に対するユーザー定義の推論ガイドが存在しない場合、および
  • 変数が空でない初期化子リスト arg1, arg2, ..., argn 指示付き初期化子 を使用可能)から初期化される場合、
集成体推論候補が追加される可能性があります。集成体推論候補のパラメータリストは、集成体の要素型から以下のように生成されます:
  • e i arg i から初期化される(再帰的な可能性のある) 集成体要素 とします。ただし、
  • 以下のいずれかの条件を満たす集成体要素については 波括弧省略 は考慮されません:
  • もし C (またはそれ自体が集成体であるその要素)が パック展開 である基底クラスを持つ場合:
  • パック展開が末尾の集成体要素である場合、初期化子リストの残りの全要素にマッチすると見なされます;
  • それ以外の場合、パックは空であると見なされます。
  • そのような e i が存在しない場合、集成体推論候補は追加されません。
  • それ以外の場合、集成体推論候補のパラメータリスト T 1 , T 2 , ..., T n を以下のように決定します:
  • もし e i が配列であり、 arg i braced-init-list である場合、 T i e i の宣言された型への右辺値参照です。
  • もし e i が配列であり、 arg i 文字列リテラル である場合、 T i e i の宣言された型へのconst修飾左辺値参照です。
  • それ以外の場合、 T i e i の宣言された型です。
  • 非末尾の集成体要素であるためにパックがスキップされた場合、元の集成体要素の位置に P j ... の形式の追加のパラメータパックが挿入されます(これは一般に推論を失敗させます)。
  • パックが末尾の集成体要素である場合、それに対応する末尾のパラメータシーケンスは T n ... の形式の単一のパラメータで置き換えられます。
集成体推論候補は、仮想的なコンストラクタ C(T 1 , T 2 , ..., T n ) から上記のように導出された架空の関数テンプレートです。
集成体推論候補に対するテンプレート引数推論中、末尾のパラメータパックの要素数は、他の方法で推論されない場合にのみ、残りの関数引数の数から推論されます。
template<class T>
struct A
{
    T t;
    struct
    {
        long a, b;
    } u;
};
A a{1, 2, 3};
// aggregate deduction candidate:
//   template<class T>
//   A<T> F(T, long, long);
template<class... Args>
struct B : std::tuple<Args...>, Args... {};
B b{std::tuple<std::any, std::string>{}, std::any{}};
// aggregate deduction candidate:
//   template<class... Args>
//   B<Args...> F(std::tuple<Args...>, Args...);
// type of b is deduced as B<std::any, std::string>
(C++20以降)

テンプレート引数推論 オーバーロード解決 が、仮想的なクラス型の架空のオブジェクトを初期化するために実行されます。この仮想クラスのコンストラクタシグネチャはガイド(戻り値の型を除く)と一致し、オーバーロード集合を形成する目的で使用されます。初期化子はクラステンプレート引数推論が実行されたコンテキストによって提供されます。ただし、 リスト初期化 の第一段階(初期化子リストコンストラクタの考慮)は、初期化子リストが単一の式から構成され、その型が(CV修飾可能性のある) U である場合に省略されます。ここで U C の特殊化、または C の特殊化から派生したクラスです。

これらの仮想的なコンストラクタは仮想クラス型の公開メンバーです。ガイドが明示的コンストラクタから形成された場合、これらは明示的となります。オーバーロード解決が失敗した場合、プログラムは不適格となります。それ以外の場合、選択された F テンプレート特殊化の戻り値型が、推定されるクラステンプレート特殊化となります。

template<class T>
struct UniquePtr
{
    UniquePtr(T* t);
};
UniquePtr dp{new auto(2.0)};
// 宣言されているコンストラクタは1つ:
// C1: UniquePtr(T*);
// 暗黙的に生成される推論ガイドのセット:
// F1: template<class T>
//     UniquePtr<T> F(T* p);
// F2: template<class T> 
//     UniquePtr<T> F(UniquePtr<T>); // コピー推論候補
// 初期化のための仮想クラス:
// struct X
// {
//     template<class T>
//     X(T* p);         // F1から
//     
//     template<class T>
//     X(UniquePtr<T>); // F2から
// };
// Xオブジェクトの直接初期化
// 初期化子として "new double(2.0)" を使用
// ガイドF1に対応するコンストラクタを選択(T = double)
// F1(T=double)の場合、戻り値の型は UniquePtr<double>
// 結果:
// UniquePtr<double> dp{new auto(2.0)}

または、より複雑な例として(注記: " S::N " はコンパイルされません:スコープ解決修飾子は推論可能な対象ではありません):

template<class T>
struct S
{
    template<class U>
    struct N
    {
        N(T);
        N(T, U);
        template<class V>
        N(V, U);
    };
};
S<int>::N x{2.0, 1};
// 暗黙的に生成される推論ガイドは以下の通り(Tは既にintであることが分かっている)
// F1: template<class U>
//     S<int>::N<U> F(int);
// F2: template<class U>
//     S<int>::N<U> F(int, U);
// F3: template<class U, class V>
//     S<int>::N<U> F(V, U);
// F4: template<class U>
//     S<int>::N<U> F(S<int>::N<U>); (コピー推論候補)
// 初期化子 "{2.0, 1}" を用いた直接リスト初期化に対するオーバーロード解決では
// U=int、V=double の F3 が選択される
// 戻り値の型は S<int>::N<int>
// 結果:
// S<int>::N<int> x{2.0, 1};

ユーザー定義の推論ガイド

ユーザー定義の導出ガイドの構文は、関数(テンプレート)宣言の構文と末尾戻り値型を持つが、関数名としてクラステンプレートの名前を使用する点が異なります:

explicit  (任意) template-name ( parameter-list ) -> simple-template-id requires-clause  (任意) ; (1)
template < template-parameter-list  > requires-clause  (任意)
explicit  (任意) template-name ( parameter-list ) -> simple-template-id requires-clause  (任意) ;
(2)
template-parameter-list - 空でないカンマ区切りの テンプレートパラメータ のリスト
explicit - explicit 指定子
template-name - 引数が推論されるクラステンプレートの名前
parameter-list - (空の場合もある) パラメータリスト
simple-template-id - 単純テンプレート識別子
requires-clause - (C++20以降) requires


ユーザー定義推論ガイドのパラメータはプレースホルダ型を持つことはできません: 省略関数テンプレート 構文は許可されていません。

(C++20以降)

ユーザー定義のデダクションガイドは、クラステンプレートの名前を指定する必要があり、クラステンプレートと同じセマンティックスコープ(名前空間または外側のクラス)内で導入されなければならず、メンバークラステンプレートの場合、同じアクセス権を持たなければなりません。ただし、デダクションガイドはそのスコープのメンバーにはなりません。

デデュクションガイドは関数ではなく、本体を持ちません。デデュクションガイドは名前探索では見つからず、 他のデデュクションガイドとのオーバーロード解決 を除いてオーバーロード解決には参加しません。デデュクションガイドは同じ翻訳単位で同じクラステンプレートに対して再宣言することはできません。

// テンプレートの宣言
template<class T>
struct container
{
    container(T t) {}
    template<class Iter>
    container(Iter beg, Iter end);
};
// 追加の推論ガイド
template<class Iter>
container(Iter b, Iter e) -> container<typename std::iterator_traits<Iter>::value_type>;
// 使用例
container c(7); // OK: 暗黙的に生成されたガイドを使用して T=int を推論
std::vector<double> v = {/* ... */};
auto d = container(v.begin(), v.end()); // OK: T=double を推論
container e{5, 6}; // エラー: std::iterator_traits<int>::value_type が存在しない

オーバーロード解決の目的で作成される仮想的なコンストラクタ(前述)は、暗黙的に生成される推論ガイドが明示的コンストラクタに対応する場合、またはユーザー定義の推論ガイドが explicit として宣言されている場合に、明示的コンストラクタとなります。常に通り、そのようなコンストラクタはコピー初期化の文脈では無視されます:

template<class T>
struct A
{
    explicit A(const T&, ...) noexcept; // #1
    A(T&&, ...);                        // #2
};
int i;
A a1 = {i, i}; // エラー: #2の右辺値参照から推論できず、
               // #1はexplicitであり、コピー初期化では考慮されない
A a2{i, i};    // OK、#1がA<int>に推論され、初期化も行う
A a3{0, i};    // OK、#2がA<int>に推論され、初期化も行う
A a4 = {0, i}; // OK、#2がA<int>に推論され、初期化も行う
template<class T>
A(const T&, const T&) -> A<T&>; // #3
template<class T>
explicit A(T&&, T&&)  -> A<T>;  // #4
A a5 = {0, 1}; // エラー: #3がA<int&>に推論され、
               // #1と#2が同じパラメータのコンストラクタになる
A a6{0, 1};    // OK、#4がA<int>に推論され、#2が初期化する
A a7 = {0, i}; // エラー: #3がA<int&>に推論される
A a8{0, i};    // エラー: #3がA<int&>に推論される
// 注記: https://github.com/cplusplus/CWG/issues/647 を参照のこと。a7とa8の例は
// 誤りであり、以下のように置き換えられる可能性があると主張している
//A a7 = {0, i}; // エラー: #2と#3の両方が一致し、オーバーロード解決に失敗
//A a8{i,i};     // エラー: #3がA<int&>に推論され、
//               //        #1と#2が同じコンストラクタを宣言する

コンストラクタまたはコンストラクタテンプレートのパラメータリストでメンバtypedefまたはエイリアステンプレートを使用しても、それだけでは、暗黙的に生成されるガイドの対応するパラメータを非推定コンテキストにすることはありません。

template<class T>
struct B
{
    template<class U>
    using TA = T;
    template<class U>
    B(U, TA<U>); // #1
};
// #1から生成される暗黙の推論ガイドは以下と同等
//     template<class T, class U>
//     B(U, T) -> B<T>;
// 以下ではなく
//     template<class T, class U>
//     B(U, typename B<T>::template TA<U>) -> B<T>;
// これは推論可能ではない
B b{(int*)0, (char*)0}; // OK、B<char*>を推論

エイリアステンプレートの推論

関数形式キャストまたは変数宣言が引数リストなしのエイリアステンプレート名 A を型指定子として使用する場合において、 A B<ArgList> のエイリアスとして定義され、 B のスコープが非依存であり、 B がクラステンプレートまたは同様に定義されたエイリアステンプレートであるとき、推論はクラステンプレートと同様に進行するが、ガイドは B のガイドから以下のように生成される:

  • B の各ガイド f について、 f の戻り値型のテンプレート引数を B<ArgList> から テンプレート引数推論 を使用して推定する(ただし、一部の引数が推定されなくても推論は失敗しない)。他の理由で推論が失敗した場合は、空の推定テンプレート引数セットで続行する。
  • 上記の推論結果を f に代入する。代入が失敗した場合はガイドは生成されない。それ以外の場合、代入結果を g とし、ガイド f' が形成される。このとき:
  • f' のパラメータ型と戻り値型は g と同じ
  • f がテンプレートの場合、 f' は関数テンプレートであり、そのテンプレートパラメータリストは、上記の推論または(再帰的に)そのデフォルトテンプレート引数に現れる A の全テンプレートパラメータ(デフォルトテンプレート引数を含む)と、推定されなかった f のテンプレートパラメータ(デフォルトテンプレート引数を含む)で構成される。 f がテンプレートでない場合、 f' は関数
  • f' の関連制約は、 g の関連制約と、 A の引数が結果型から推定可能である場合にのみ満たされる制約との論理積
template<class T>
class unique_ptr
{
    /* ... */
};
template<class T>
class unique_ptr<T[]>
{
    /* ... */
};
template<class T>
unique_ptr(T*) -> unique_ptr<T>;   // #1
template<class T>
unique_ptr(T*) -> unique_ptr<T[]>; // #2
template<class T>
concept NonArray = !std::is_array_v<T>;
template<NonArray A>
using unique_ptr_nonarray = unique_ptr<A>;
template<class A>
using unique_ptr_array = unique_ptr<A[]>;
// unique_ptr_nonarray に対して生成されるガイド:
// #1 から (unique_ptr<T> を unique_ptr<A> から推定すると T = A):
// template<class A>
//     requires(argument_of_unique_ptr_nonarray_is_deducible_from<unique_ptr<A>>)
// auto F(A*) -> unique_ptr<A>;
// #2 から (unique_ptr<T[]> を unique_ptr<A> から推定すると何も得られない):
// template<class T>
//     requires(argument_of_unique_ptr_nonarray_is_deducible_from<unique_ptr<T[]>>)
// auto F(T*) -> unique_ptr<T[]>;
// ここで argument_of_unique_ptr_nonarray_is_deducible_from は以下のように定義可能:
// template<class>
// class AA;
// template<NonArray A>
// class AA<unique_ptr_nonarray<A>> {};
// template<class T>
// concept argument_of_unique_ptr_nonarray_is_deducible_from =
//     requires { sizeof(AA<T>); };
// unique_ptr_array に対して生成されるガイド:
// #1 から (unique_ptr<T> を unique_ptr<A[]> から推定すると T = A[]):
// template<class A>
//     requires(argument_of_unique_ptr_array_is_deducible_from<unique_ptr<A[]>>)
// auto F(A(*)[]) -> unique_ptr<A[]>;
// #2 から (unique_ptr<T[]> を unique_ptr<A[]> から推定すると T = A):
// template<class A>
//     requires(argument_of_unique_ptr_array_is_deducible_from<unique_ptr<A[]>>)
// auto F(A*) -> unique_ptr<A[]>;
// ここで argument_of_unique_ptr_array_is_deducible_from は以下のように定義可能:
// template<class>
// class BB;
// template<class A>
// class BB<unique_ptr_array<A>> {};
// template<class T>
// concept argument_of_unique_ptr_array_is_deducible_from =
//     requires { sizeof(BB<T>); };
// 使用例:
unique_ptr_nonarray p(new int); // unique_ptr<int> に推定
// #1 から生成された推論ガイドは unique_ptr<int> を返す
// #2 から生成された推論ガイドは unique_ptr<int[]> を返すが無視される
//   argument_of_unique_ptr_nonarray_is_deducible_from<unique_ptr<int[]>> が不満足のため
unique_ptr_array q(new int[42]); // unique_ptr<int[]> に推定
// #1 から生成された推論ガイドは失敗 (new int[42] から A(*)[] の A を推定できない)
// #2 から生成された推論ガイドは unique_ptr<int[]> を返す
(C++20 以降)

注記

クラステンプレートの引数推論は、テンプレート引数リストが存在しない場合にのみ行われます。テンプレート引数リストが指定されている場合、推論は行われません。

std::tuple t1(1, 2, 3);                // OK: 型推論
std::tuple<int, int, int> t2(1, 2, 3); // OK: 全ての引数が指定されている
std::tuple<> t3(1, 2, 3);    // エラー: tuple<>に一致するコンストラクタが存在しない
                             //        型推論は実行されない
std::tuple<int> t4(1, 2, 3); // エラー

集約型のクラステンプレート引数推定には、通常ユーザー定義の推定ガイドが必要です:

template<class A, class B>
struct Agg
{
    A a;
    B b;
};
// implicitly-generated guides are formed from default, copy, and move constructors
template<class A, class B>
Agg(A a, B b) -> Agg<A, B>;
// ^ This deduction guide can be implicitly generated in C++20
Agg agg{1, 2.0}; // deduced to Agg<int, double> from the user-defined guide
template<class... T>
array(T&&... t) -> array<std::common_type_t<T...>, sizeof...(T)>;
auto a = array{1, 2, 5u}; // deduced to array<unsigned, 3> from the user-defined guide
(C++20まで)

ユーザー定義のデダクションガイドはテンプレートである必要はありません:

template<class T>
struct S
{
    S(T);
};
S(char const*) -> S<std::string>;
S s{"hello"}; // S<std::string> に推論される

クラステンプレートのスコープ内では、パラメータリストなしのテンプレート名は注入されたクラス名であり、型として使用できます。この場合、クラス引数推論は行われず、テンプレートパラメータは明示的に指定する必要があります:

template<class T>
struct X
{
    X(T) {}
    template<class Iter>
    X(Iter b, Iter e) {}
    template<class Iter>
    auto foo(Iter b, Iter e)
    {
        return X(b, e); // 推論なし: Xは現在のX<T>を指す
    }
    template<class Iter>
    auto bar(Iter b, Iter e)
    {
        return X<typename Iter::value_type>(b, e); // 明示的に指定が必要
    }
    auto baz()
    {
        return ::X(0); // 注入されたクラス名ではない; X<int>と推論される
    }
};

オーバーロード解決 において、部分順序付けは関数テンプレートがユーザー定義推論ガイドから生成されたかどうかよりも優先されます:コンストラクタから生成された関数テンプレートがユーザー定義推論ガイドから生成されたものよりも特殊化されている場合、コンストラクタから生成された方が選択されます。コピー推論候補は通常、ラッピングコンストラクタよりも特殊化されているため、この規則は一般にコピーがラッピングよりも優先されることを意味します。

template<class T>
struct A
{
    A(T, int*);     // #1
    A(A<T>&, int*); // #2
    enum { value };
};
template<class T, int N = T::value>
A(T&&, int*) -> A<T>; //#3
A a{1, 0}; // #1を使用してA<int>を推論し、#1で初期化
A b{a, 0}; // #2(#3より特殊化されている)を使用してA<int>を推論し、#2で初期化

部分順序付けを含む以前のタイブレーカーが2つの候補関数テンプレートを区別できなかった場合、以下の規則が適用されます:

  • ユーザー定義の推論ガイドから生成された関数テンプレートは、コンストラクタまたはコンストラクタテンプレートから暗黙的に生成されたものよりも優先されます。
  • コピー推論候補は、コンストラクタまたはコンストラクタテンプレートから暗黙的に生成された他のすべての関数テンプレートよりも優先されます。
  • 非テンプレートコンストラクタから暗黙的に生成された関数テンプレートは、コンストラクタテンプレートから暗黙的に生成された関数テンプレートよりも優先されます。
template<class T>
struct A
{
    using value_type = T;
    A(value_type); // #1
    A(const A&);   // #2
    A(T, T, int);  // #3
    template<class U>
    A(int, T, U);  // #4
};                 // #5, コピー推論候補 A(A);
A x(1, 2, 3); // #3を使用、非テンプレートコンストラクタから生成
template<class T>
A(T) -> A<T>; // #6, #5よりも特殊化度が低い
A a(42); // #6を使用してA<int>を推論し、#1で初期化
A b = a; // #5を使用してA<int>を推論し、#2で初期化
template<class T>
A(A<T>) -> A<A<T>>; // #7, #5と同等の特殊化度
A b2 = a; // #7を使用してA<A<int>>を推論し、#1で初期化

cv修飾されていないテンプレートパラメータへの右辺値参照は、そのパラメータがクラステンプレートパラメータである場合、 転送参照 ではありません:

template<class T>
struct A
{
    template<class U>
    A(T&&, U&&, int*); // #1: T&& は forwarding reference ではない
                       //     U&& は forwarding reference である
    A(T&&, int*);      // #2: T&& は forwarding reference ではない
};
template<class T>
A(T&&, int*) -> A<T>; // #3: T&& は forwarding reference である
int i, *ip;
A a{i, 0, ip};  // エラー: #1 から推論できない
A a0{0, 0, ip}; // #1 を使用して A<int> を推論し、#1 を使用して初期化
A a2{i, ip};    // #3 を使用して A<int&> を推論し、#2 を使用して初期化

単一の引数から初期化する際、その型が問題のクラステンプレートの特殊化である場合、デフォルトではラッピングよりもコピー推論が優先されます:

std::tuple t1{1};  //std::tuple<int>
std::tuple t2{t1}; //std::tuple<int>、std::tuple<std::tuple<int>>ではない
std::vector v1{1, 2};   // std::vector<int>
std::vector v2{v1};     // std::vector<int>、std::vector<std::vector<int>>ではない (P0702R1)
std::vector v3{v1, v2}; // std::vector<std::vector<int>>

コピーとラッピングの特別なケースを除いて、リスト初期化における初期化子リストコンストラクタの強い優先順位は維持されます。

std::vector v1{1, 2}; // std::vector<int>
std::vector v2(v1.begin(), v1.end()); // std::vector<int>
std::vector v3{v1.begin(), v1.end()}; // std::vector<std::vector<int>::iterator>
**注釈**: 元のテキストは既にC++コードとコメントで構成されており、翻訳対象となる自然言語のテキストが含まれていません。HTMLタグ、属性、コードブロック内のテキストは翻訳せず、C++専門用語も保持するという指示に従いました。

クラステンプレート引数推論が導入される前、引数を明示的に指定することを避ける一般的なアプローチは、関数テンプレートを使用することでした:

std::tuple p1{1, 1.0};             //std::tuple<int, double>、型推論を使用
auto p2 = std::make_tuple(1, 1.0); //std::tuple<int, double>、C++17以前
機能テストマクロ 規格 機能
__cpp_deduction_guides 201703L (C++17) クラステンプレートのテンプレート引数推論
201907L (C++20) 集成体とエイリアスに対するCTAD

不具合報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR 適用バージョン 公開時の動作 修正後の動作
CWG 2376 C++17 変数宣言の型が引数推定対象のクラステンプレートと異なる場合でも
CTADが実行されていた
この場合CTADを
実行しない
CWG 2628 C++20 暗黙のdeduction guideが制約を伝播しなかった 制約を伝播する
CWG 2697 C++20 ユーザー定義deduction guideで省略関数テンプレート構文が
許可されるか不明確だった
禁止
CWG 2707 C++20 deduction guideがトレイリング requires 節を持てなかった 持つことができる
CWG 2714 C++17 暗黙のdeduction guideがコンストラクタの
デフォルト引数を考慮していなかった
考慮する
CWG 2913 C++20 CWG issue 2707 の解決によりdeduction guideの構文が
関数宣言の構文と一貫性がなくなった
構文を調整
P0702R1 C++17 initializer-listコンストラクタがcopy deduction candidateを
優先し、ラッピングが発生することがあった
コピー時にinitializer-listフェーズを
スキップする