【问题标题】:CTAD and designated initializers in C++20C++20 中的 CTAD 和指定初始值设定项
【发布时间】:2020-01-13 03:31:53
【问题描述】:

我已经在 question 中说明了对带有指定初始化程序的 CTAD 的困惑,但我对非常相似的代码 sn-p 有另一个困惑

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),演绎指南显然只关心初始化程序中的顺序。扣分指南应该聪明点还是应该有“指定扣分指南”?

查看https://godbolt.org/z/cm6Yi7上的示例

【问题讨论】:

  • 演绎指南确实有点糊弄水了

标签: c++ c++20 designated-initializer ctad


【解决方案1】:

请参阅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-listdesignated-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>;

模板参数总是来自主类模板,所以我们从那里引入默认模板参数。候选参数来自initializer-listsecond 的类型为U

聚合推理候选是最佳候选(只有聚合推理候选和推理指南可行,聚合推理候选更专业),所以我们最终得到my_pair&lt;int, float&gt;


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

my_pair<int, float> x{.second = 20.f};

哪个有效,并导致 x.first{} 初始化。


用于聚合的 CTAD 是最近才通过的(在 2019 年 7 月的科隆会议上,两个月前)。在该功能之前,这仍然是格式良好的:

my_pair{.second = 20.f};

为什么?我们还没有综合扣除候选,但我们仍然有扣除指南......这可行的。它给了我们my_pair&lt;float&gt;。也就是说,my_pair&lt;float, float&gt; 一旦你填写了U 的默认模板参数。

这就是 gcc 为您提供您所看到的行为的原因 - 它只是尚未为聚合实现 CTAD,而是为您提供旧的行为。

【讨论】:

  • 但我最终得到了my_pair&lt;float, float&gt;。根据你的回答(和我的逻辑思维),我不应该..
  • 所以,解决帖子中的问题。 first 被推断为 float 是一个编译器错误。
  • @kawillzocken 添加了一个更新来解释为什么你最终会得到my_pair&lt;float, float&gt;。这不是编译器错误,而是编译器尚未实现的此功能。
  • 嗯,GCC 9.1、Clang 9 和 VS 2019 16.1 都实现了 CTAD 和指定的初始化程序,没有一个实现了聚合的 CTAD。但只有 GCC 首先推断为浮点数。所以至少有一个编译器有问题。并且 GCC 有忽略指示符的记录。
猜你喜欢
  • 2020-07-20
  • 2020-01-13
  • 2020-03-11
  • 1970-01-01
  • 2016-05-15
  • 1970-01-01
  • 1970-01-01
  • 2016-01-22
相关资源
最近更新 更多