C++20 中的 CTAD 和指定初始化程序
CTAD and designated initializers in C++20
我已经在这个 中表达了对 CTAD 与指定初始值设定项的混淆,但我对非常相似的代码片段有另一个混淆
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{.second = 20.f};
static_assert( std::is_same_v<decltype(x.first), int> ); //FAILS <- its deduced to float
static_assert( std::is_same_v<decltype(x.second), float> );
}
推导指南似乎导致 first
的类型被推导为 float
,即使我没有在指定的初始化程序中给出明确的 .first
。推导指南显然只关心初始化程序中的顺序,而不管关键字 (.second
)。演绎指南应该对此精明还是应该有一个"designated deduction guide"?
上的示例
以 this answer 为起点。我们有相同的初始三个候选人:
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...>;
而合计扣除候选者是根据我们实际提供的initializer-list或指定-initializer-list ,而不是聚合的实际基础成员。我们的 designated-initializer-list 是 {.second = 20.f}
所以我们的合计扣除候选人变成:
// aggregate deduction candidate
template <class T=int, class U=float>
auto __f(U) -> my_pair<T, U>;
模板参数始终来自主 class 模板,因此我们从那里引入默认模板参数。候选参数来自initializer-list,second
的类型是U
.
聚合推导候选是最佳候选(只有聚合推导候选和推导指南可行,聚合推导候选更专业),所以我们最终得到my_pair<int, float>
。
完成 CTAD 后,我们现在重新开始并有效地做
my_pair<int, float> x{.second = 20.f};
有效,并导致 x.first
从 {}
初始化。
用于聚合的 CTAD 直到最近才通过(两个月前在 2019 年 7 月的科隆会议上)。在该功能之前,这仍然是 well-formed:
my_pair{.second = 20.f};
为什么?我们还没有综合扣除候选,但我们仍然有扣除指南......是可行的。它给了我们 my_pair<float>
。也就是说,my_pair<float, float>
填写 U
.
的默认模板参数后
这就是为什么 gcc 给你你看到的行为 - 它只是还没有为聚合实现 CTAD,并且给你旧的行为。
我已经在这个
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{.second = 20.f};
static_assert( std::is_same_v<decltype(x.first), int> ); //FAILS <- its deduced to float
static_assert( std::is_same_v<decltype(x.second), float> );
}
推导指南似乎导致 first
的类型被推导为 float
,即使我没有在指定的初始化程序中给出明确的 .first
。推导指南显然只关心初始化程序中的顺序,而不管关键字 (.second
)。演绎指南应该对此精明还是应该有一个"designated deduction guide"?
以 this answer 为起点。我们有相同的初始三个候选人:
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...>;
而合计扣除候选者是根据我们实际提供的initializer-list或指定-initializer-list ,而不是聚合的实际基础成员。我们的 designated-initializer-list 是 {.second = 20.f}
所以我们的合计扣除候选人变成:
// aggregate deduction candidate
template <class T=int, class U=float>
auto __f(U) -> my_pair<T, U>;
模板参数始终来自主 class 模板,因此我们从那里引入默认模板参数。候选参数来自initializer-list,second
的类型是U
.
聚合推导候选是最佳候选(只有聚合推导候选和推导指南可行,聚合推导候选更专业),所以我们最终得到my_pair<int, float>
。
完成 CTAD 后,我们现在重新开始并有效地做
my_pair<int, float> x{.second = 20.f};
有效,并导致 x.first
从 {}
初始化。
用于聚合的 CTAD 直到最近才通过(两个月前在 2019 年 7 月的科隆会议上)。在该功能之前,这仍然是 well-formed:
my_pair{.second = 20.f};
为什么?我们还没有综合扣除候选,但我们仍然有扣除指南......是可行的。它给了我们 my_pair<float>
。也就是说,my_pair<float, float>
填写 U
.
这就是为什么 gcc 给你你看到的行为 - 它只是还没有为聚合实现 CTAD,并且给你旧的行为。