具有模板类型的C ++ 20指定的初始值设定项

kaw*_*ken 8 c++ designated-initializer class-template argument-deduction c++20

指定的初始化程序(C ++ 20)应该如何与CTAD一起使用?

这段代码在gcc9.2中可以正常工作,但在clang8中失败

template <typename int_t=int, typename float_t=float>
struct my_pair {
    int_t   first;
    float_t second;
};

template<typename ... ts>
my_pair(ts...) -> my_pair<ts...>;

int main() {
    my_pair x{.first = 20, .second = 20.f};
    static_assert( std::is_same_v<decltype(x.first), int> );
    static_assert( std::is_same_v<decltype(x.second), float> );
}
Run Code Online (Sandbox Code Playgroud)

这应该是有效的吗?

参见https://godbolt.org/z/KtNI43上的示例

Bar*_*rry 4

是的,这应该是有效的。

CTAD 的工作方式是我们对一组合成的构造函数执行重载解析,以找出类模板参数是什么。从 C++17 开始,合成的构造函数集仅基于主模板的构造函数和推导指南(我正在更改模板参数名称,因为我发现它们非常混乱):

template <class T=int, class U=float>
struct my_pair {
    T first;
    U second;
};

// default constructor
template <class T=int, class U=float>
auto __f() -> my_pair<T, U>;

// copy candidate
template <class T=int, class U=float>
auto __f(my_pair<T, U>) -> my_pair<T, U>;

// deduction guide
template <class... T>
auto __f(T...) -> my_pair<T...>;
Run Code Online (Sandbox Code Playgroud)

C++20 添加了新的聚合推导候选。对于初始值设定项列表指定初始值设定项列表的每个元素,我们选择聚合的相应元素并使用其类型作为新的候选者。为了

my_pair x{.first = 20, .second = 20.f};
Run Code Online (Sandbox Code Playgroud)

firstis的类型和isT的类型,因此:secondU

// aggregate deduction candidate
template <class T=int, class U=float>
auto __f(T, U) -> my_pair<T, U>;
Run Code Online (Sandbox Code Playgroud)

现在,我将这四个候选者写为函数(因为我发现将它们视为函数更容易),但措辞将它们定义为假设类类型的构造函数。因此,当我们使用 执行重载解析时{.first = 20, .second = 20.f},如果你眯着眼睛看,它是有效的。

最后一个候选者是最佳候选者(只有聚合推导候选者和推导指南可行,聚合推导候选者更专​​业),所以我们最终得到my_pair<int, float>


完成 CTAD 后,我们现在重新开始并有效地做

my_pair<int, float> x{.first = 20, .second = 20.f};
Run Code Online (Sandbox Code Playgroud)

这当然有效。