See 这个答案 https://stackoverflow.com/q/57886451/2069064作为起点。我们有相同的最初三个候选人:
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...>;
且合计扣除候选者以实际情况为准初始化列表 or 指定初始化列表我们提供的不是聚合的实际底层成员。我们的指定初始化列表 is {.second = 20.f}
所以我们的总扣除候选人变成:
// aggregate deduction candidate
template <class T=int, class U=float>
auto __f(U) -> my_pair<T, U>;
模板参数始终来自主类模板,因此我们从那里引入默认模板参数。候选人的论点来自于初始化列表,以及类型second
is U
.
聚合推导候选是最佳候选(只有聚合推导候选和推导指南可行,聚合推导候选更专业),所以我们最终得到my_pair<int, float>
.
完成 CTAD 后,我们现在重新开始并有效地做
my_pair<int, float> x{.second = 20.f};
这有效并导致x.first
正在初始化自{}
.
CTAD 总量最近才被采用(两个月前,2019 年 7 月的科隆会议上)。在该功能出现之前,这仍然是格式良好的:
my_pair{.second = 20.f};
为什么?我们还没有总计扣除候选人,但我们仍然有扣除指南......其中is可行的。它给我们my_pair<float>
。也就是说,my_pair<float, float>
一旦您填写了默认模板参数U
.
这就是为什么 gcc 给你你所看到的行为 - 它只是还没有为聚合实现 CTAD,并且给你旧的行为。