C++20指定初始化器与模板类型

14

指定初始化器(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> );
}

这是否应该是有效的?

https://godbolt.org/z/KtNI43上查看示例。


1
我在这里链接了一个相当相关的问题,因为答案可能对两者都很有趣。 - nnolte
1个回答

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...>;

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

my_pair x{.first = 20, .second = 20.f};

first的类型是Tsecond的类型是U,因此:

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

现在,我将这四个候选项写成了函数(因为我觉得将它们视为函数更容易思考),但措辞将它们定义为一个假设类类型的构造函数。因此,当我们使用{.first = 20, .second = 20.f}进行重载决议时,如果你眯起眼睛看,它有点奏效。
最后一个候选者是最佳候选者(只有聚合推导候选和模板参数推导指南可行,聚合推导候选更加专业化),因此我们最终获得了my_pair<int, float>
完成CTAD后,我们现在重新开始并有效地执行
my_pair<int, float> x{.first = 20, .second = 20.f};

当然可以运作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接