名前空間
変種
操作

クラステンプレート引数推論 (CTAD) (C++17以降)

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 
 
 

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

  • 宣言された型がクラステンプレートである(おそらくcv修飾された)変数および変数テンプレートの初期化を指定する、あらゆる宣言
std::pair p(2, 4.5);     // deduces to std::pair<int, double> p(2, 4.5);
std::tuple t(4, 3, 2.5); // same as auto t = std::make_tuple(4, 3, 2.5);
std::less l;             // same as std::less<void> l;
template<class T>
struct A
{
    A(T, T);
};
 
auto y = new A{1, 2}; // allocated type is A<int>
auto lck = std::lock_guard(mtx);     // deduces to std::lock_guard<std::mutex>
std::copy_n(vi1, 3,
    std::back_insert_iterator(vi2)); // deduces to std::back_insert_iterator<T>,
                                     // where T is the type of the container vi2
std::for_each(vi.begin(), vi.end(),
    Foo([&](int i) {...}));          // deduces to Foo<T>,
                                     // where T is the unique lambda type
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が定義されている場合、指定されたプライマリテンプレートで宣言されている各コンストラクタ(またはコンストラクタテンプレート)Ciについて、以下のすべての条件を満たす仮想関数テンプレートFiが構築されます。
  • Fiのテンプレートパラメータは、Cのテンプレートパラメータに続いて(Ciがコンストラクタテンプレートの場合)Ciのテンプレートパラメータです(デフォルトテンプレート引数も含まれます)。
  • Fi関連する制約は、Cの関連する制約とCiの関連する制約の論理積です。
(C++20以降)
  • Fiパラメータリストは、Ciのパラメータリストです。
  • Fiの戻り値の型は、Cに続いてクラステンプレートのテンプレートパラメータが<>で囲まれたものです。
  • Cが定義されていないか、コンストラクタを宣言していない場合、仮想コンストラクタC()から上記のように派生した追加の仮想関数テンプレートが追加されます。
  • いずれの場合も、仮想コンストラクタC(C)から上記のように派生した追加の仮想関数テンプレートが追加され、これはコピー推論候補と呼ばれます。
  • Fiのパラメータリストは、Giのパラメータリストです。
  • Fiの戻り値の型は、Giの単純なテンプレート識別子です。
  • Giがテンプレートパラメータを持つ場合(構文(2))、Fiは関数テンプレートであり、そのテンプレートパラメータリストはGiのテンプレートパラメータリストです。それ以外の場合、Fiは関数です。
  • さらに、もし
  • Cが定義されており、依存基底クラスに仮想関数や仮想基底クラスがないと仮定した場合に集約型の要件を満たしている。
  • Cに対するユーザー定義推論ガイドが存在せず、
  • 変数が空でない初期化子リストarg1, arg2, ..., argn指定初期化子を使用することも可能)で初期化されている場合、
集約推論候補が追加されることがあります。集約推論候補のパラメータリストは、集約要素型から次のように生成されます。
  • argiから初期化される(おそらく再帰的な)集約要素eiとすると、ここで
  • 波括弧省略は、以下のいずれかの集約要素に対しては考慮されません。
  • C(またはそれ自体が集約であるその要素)がパック展開である基底を持つ場合
  • パック展開が末尾の集約要素である場合、それは初期化子リストの残りのすべての要素にマッチすると見なされます。
  • それ以外の場合、パックは空であると見なされます。
  • そのようなeiが存在しない場合、集約推論候補は追加されません。
  • それ以外の場合、集約推論候補のパラメータリストT1, T2, ..., Tnを次のように決定します。
  • eiが配列でargi波括弧初期化リストの場合、Tieiの宣言された型への右辺値参照です。
  • eiが配列でargi文字列リテラルの場合、Tieiのconst修飾された宣言された型への左辺値参照です。
  • それ以外の場合、Tieiの宣言された型です。
  • パックが非末尾の集約要素であるためにスキップされた場合、その元の集約要素の位置にPj ...形式の追加のパラメータパックが挿入されます。(これは通常、推論を失敗させます。)
  • パックが末尾の集約要素である場合、それに対応するパラメータの末尾シーケンスは、Tn ...形式の単一のパラメータに置き換えられます。
集約推論候補は、仮想コンストラクタC(T1, T2, ..., Tn)から上記のように派生した仮想関数テンプレートです。
集約推論候補のテンプレート引数推論中、末尾のパラメータパックの要素数は、他に推論されない場合にのみ、残りの関数引数の数から推論されます。
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以降)

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

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

template<class T>
struct UniquePtr
{
    UniquePtr(T* t);
};
 
UniquePtr dp{new auto(2.0)};
 
// One declared constructor:
// C1: UniquePtr(T*);
 
// Set of implicitly-generated deduction guides:
 
// F1: template<class T>
//     UniquePtr<T> F(T* p);
 
// F2: template<class T> 
//     UniquePtr<T> F(UniquePtr<T>); // copy deduction candidate
 
// imaginary class to initialize:
// struct X
// {
//     template<class T>
//     X(T* p);         // from F1
//     
//     template<class T>
//     X(UniquePtr<T>); // from F2
// };
 
// direct-initialization of an X object
// with "new double(2.0)" as the initializer
// selects the constructor that corresponds to the guide F1 with T = double
// For F1 with T=double, the return type is UniquePtr<double>
 
// result:
// 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};
 
// the implicitly-generated deduction guides are (note that T is already known to be 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>); (copy deduction candidate)
 
// Overload resolution for direct-list-init with "{2.0, 1}" as the initializer
// chooses F3 with U=int and V=double.
// The return type is S<int>::N<int>
 
// result:
// S<int>::N<int> x{2.0, 1};

[編集] ユーザー定義推論ガイド

ユーザー定義推論ガイドの構文は、関数(テンプレート)宣言の構文に後置戻り値の型が付いたものですが、関数名としてクラステンプレートの名前を使用します。

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


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

(C++20以降)

ユーザー定義推論ガイドはクラステンプレート名を指定しなければならず、クラステンプレートと同じ意味スコープ(名前空間または囲むクラス)内で導入されなければなりません。メンバクラステンプレートの場合、同じアクセス権を持たなければなりませんが、推論ガイドはそのスコープのメンバにはなりません。

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

// declaration of the template
template<class T>
struct container
{
    container(T t) {}
 
    template<class Iter>
    container(Iter beg, Iter end);
};
 
// additional deduction guide
template<class Iter>
container(Iter b, Iter e) -> container<typename std::iterator_traits<Iter>::value_type>;
 
// uses
container c(7); // OK: deduces T=int using an implicitly-generated guide
std::vector<double> v = {/* ... */};
auto d = container(v.begin(), v.end()); // OK: deduces T=double
container e{5, 6}; // Error: there is no std::iterator_traits<int>::value_type

オーバーロード解決の目的のための仮想コンストラクタ(上記で説明)は、明示的なコンストラクタから形成された暗黙的に生成される推論ガイド、またはexplicitと宣言されたユーザー定義推論ガイドに対応する場合に、explicitになります。常にそうですが、そのようなコンストラクタはコピー初期化コンテキストでは無視されます。

template<class T>
struct A
{
    explicit A(const T&, ...) noexcept; // #1
    A(T&&, ...);                        // #2
};
 
int i;
A a1 = {i, i}; // error: cannot deduce from rvalue reference in #2,
               // and #1 is explicit, and not considered in copy-initialization.
A a2{i, i};    // OK, #1 deduces to A<int> and also initializes
A a3{0, i};    // OK, #2 deduces to A<int> and also initializes
A a4 = {0, i}; // OK, #2 deduces to A<int> and also initializes
 
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}; // error: #3 deduces to A<int&>
               // and #1 & #2 result in same parameter constructors.
A a6{0, 1};    // OK, #4 deduces to A<int> and #2 initializes
A a7 = {0, i}; // error: #3 deduces to A<int&>
A a8{0, i};    // error: #3 deduces to A<int&>
 
// Note: check https://github.com/cplusplus/CWG/issues/647, claiming that
// examples a7 and a8 are incorrect, to be possibly replaced as
//A a7 = {0, i}; // error: #2 and #3 both match, overload resolution fails
//A a8{i,i};     // error: #3 deduces to A<int&>,
//               //        #1 and #2 declare same constructor

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

template<class T>
struct B
{
    template<class U>
    using TA = T;
 
    template<class U>
    B(U, TA<U>); // #1
};
 
// Implicit deduction guide generated from #1 is the equivalent of
//     template<class T, class U>
//     B(U, T) -> B<T>;
// rather than
//     template<class T, class U>
//     B(U, typename B<T>::template TA<U>) -> B<T>;
// which would not have been deducible
 
B b{(int*)0, (char*)0}; // OK, deduces B<char*>

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

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

  • Bの各ガイドfについて、テンプレート引数推論を使用してB<ArgList>からfの戻り値の型のテンプレート引数を推論します。ただし、一部の引数が推論されなくても推論は失敗しません。他の理由で推論が失敗した場合、推論されたテンプレート引数の空のセットで続行します。
  • 上記の推論の結果を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[]>;
 
// generated guide for unique_ptr_nonarray:
 
// from #1 (deduction of unique_ptr<T> from unique_ptr<A> yields T = A):
// template<class A>
//     requires(argument_of_unique_ptr_nonarray_is_deducible_from<unique_ptr<A>>)
// auto F(A*) -> unique_ptr<A>;
 
// from #2 (deduction of unique_ptr<T[]> from unique_ptr<A> yields nothing):
// template<class T>
//     requires(argument_of_unique_ptr_nonarray_is_deducible_from<unique_ptr<T[]>>)
// auto F(T*) -> unique_ptr<T[]>;
 
// where argument_of_unique_ptr_nonarray_is_deducible_from can be defined as
 
// 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>); };
 
// generated guide for unique_ptr_array:
 
// from #1 (deduction of unique_ptr<T> from unique_ptr<A[]> yields T = A[]):
// template<class A>
//     requires(argument_of_unique_ptr_array_is_deducible_from<unique_ptr<A[]>>)
// auto F(A(*)[]) -> unique_ptr<A[]>;
 
// from #2 (deduction of unique_ptr<T[]> from unique_ptr<A[]> yields T = A):
// template<class A>
//     requires(argument_of_unique_ptr_array_is_deducible_from<unique_ptr<A[]>>)
// auto F(A*) -> unique_ptr<A[]>;
 
// where argument_of_unique_ptr_array_is_deducible_from can be defined as
 
// 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>); };
 
// Use:
unique_ptr_nonarray p(new int); // deduced to unique_ptr<int>
// deduction guide generated from #1 returns unique_ptr<int>
// deduction guide generated from #2 returns unique_ptr<int[]>, which is ignored because
//   argument_of_unique_ptr_nonarray_is_deducible_from<unique_ptr<int[]>> is unsatisfied
 
unique_ptr_array q(new int[42]); // deduced to unique_ptr<int[]>
// deduction guide generated from #1 fails (cannot deduce A in A(*)[] from new int[42])
// deduction guide generated from #2 returns unique_ptr<int[]>
(C++20以降)

[編集] 注釈

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

std::tuple t1(1, 2, 3);                // OK: deduction
std::tuple<int, int, int> t2(1, 2, 3); // OK: all arguments are provided
 
std::tuple<> t3(1, 2, 3);    // Error: no matching constructor in tuple<>.
                             //        No deduction performed.
std::tuple<int> t4(1, 2, 3); // Error

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

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"}; // deduced to 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); // no deduction: X is the current X<T>
    }
 
    template<class Iter>
    auto bar(Iter b, Iter e)
    {
        return X<typename Iter::value_type>(b, e); // must specify what we want
    }
 
    auto baz()
    {
        return ::X(0); // not the injected-class-name; deduced to be 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}; // uses #1 to deduce A<int> and initializes with #1
A b{a, 0}; // uses #2 (more specialized than #3) to deduce A<int> and initializes with #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, the copy deduction candidate A(A);
 
A x(1, 2, 3); // uses #3, generated from a non-template constructor
 
template<class T>
A(T) -> A<T>; // #6, less specialized than #5
 
A a(42); // uses #6 to deduce A<int> and #1 to initialize
A b = a; // uses #5 to deduce A<int> and #2 to initialize
 
template<class T>
A(A<T>) -> A<A<T>>; // #7, as specialized as #5
 
A b2 = a; // uses #7 to deduce A<A<int>> and #1 to initialize

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

template<class T>
struct A
{
    template<class U>
    A(T&&, U&&, int*); // #1: T&& is not a forwarding reference
                       //     U&& is a forwarding reference
 
    A(T&&, int*);      // #2: T&& is not a forwarding reference
};
 
template<class T>
A(T&&, int*) -> A<T>; // #3: T&& is a forwarding reference
 
int i, *ip;
A a{i, 0, ip};  // error, cannot deduce from #1
A a0{0, 0, ip}; // uses #1 to deduce A<int> and #1 to initialize
A a2{i, ip};    // uses #3 to deduce A<int&> and #2 to initialize

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

std::tuple t1{1};  //std::tuple<int>
std::tuple t2{t1}; //std::tuple<int>, not std::tuple<std::tuple<int>>
 
std::vector v1{1, 2};   // std::vector<int>
std::vector v2{v1};     // std::vector<int>, not 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>

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

std::tuple p1{1, 1.0};             //std::tuple<int, double>, using deduction
auto p2 = std::make_tuple(1, 1.0); //std::tuple<int, double>, pre-C++17
機能テストマクロ 規格 機能
__cpp_deduction_guides 201703L (C++17) クラステンプレートのテンプレート引数推論
201907L (C++20) 集約とエイリアスのCTAD

[編集] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 2376 C++17 宣言された変数の型が
引数が推論されるクラステンプレートとは異なる場合でもCTADが実行される
この場合、CTADを
実行しない
CWG 2628 C++20 暗黙的な推論ガイドが制約を伝播しなかった 制約を伝播する
CWG 2697 C++20 省略された関数テンプレート構文が
ユーザー定義推論ガイドで許可されているか不明確であった
禁止された
CWG 2707 C++20 推論ガイドが後置requires句を持てなかった できるようになった
CWG 2714 C++17 暗黙的な推論ガイドが
コンストラクタのデフォルト引数を考慮しなかった
それらを考慮する
CWG 2913 C++20 CWG issue 2707の解決により、推論ガイドの
構文が関数宣言構文と矛盾した
構文を調整した
P0702R1 C++17 初期化子リストコンストラクタが
コピー推論候補を先取りし、ラッピングを引き起こす可能性がある
初期化子リストフェーズは
コピー時にスキップされる
English 日本語 中文(简体) 中文(繁體)