C++20 designated initializers with templated types

岁酱吖の 提交于 2019-12-08 17:00:48

问题


How are designated initializers (C++20) supposed to work with CTAD?

This code works fine in gcc9.2, but fails with 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> );
}

Is this supposed to be valid?

See an example on https://godbolt.org/z/KtNI43


回答1:


Yes, this is supposed to be valid.

The way CTAD works is we perform overload resolution over a synthesized set of constructors to figure out what the class template parameters were. From C++17, that synthesized set of constructors is just based on the primary template's constructors and deduction guides (I'm changing the template parameter names because I find them very confusing):

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 adds a new aggregate deduction candidate. For each element of either the initializer-list or designated-initializer-list, we pick the corresponding element of the aggregate and use its type as the new candidate. For

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

The type of first is T and the type of second is U, hence:

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

Now, I wrote these four candidates as functions (because I find it easier to think of them as functions) but the wording defines them as constructors of a hypothetical class type. So when we perform overload resolution using {.first = 20, .second = 20.f}, if you squint it kind of works.

The last candidate is the best candidate (only the aggregate deduction candidate and the deduction guide are viable, the aggregate deduction candidate is more specialized), so we end up with my_pair<int, float>.


Having finished CTAD, we now start over and effectively do

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

Which of course works.



来源:https://stackoverflow.com/questions/57886451/c20-designated-initializers-with-templated-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!