简体   繁体   中英

C++20 designated initializers with templated types

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM