CTAD and designated initializers in C++20

只谈情不闲聊 提交于 2019-12-07 00:05:10

问题


I have already stated confusion about CTAD with designated initializers in this question, but i have another confusion with a very similar code snippet

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> );
}

It seems like the deduction guide causes the type of first to be deduced to float, even though i do not give an explicit .first in the designated initializer. The deduction guide apparently only cares about the order in the initializer, no matter the keyword (.second). Should the deduction guide be smart about this or should there be a "designated deduction guide"?

See the example on https://godbolt.org/z/cm6Yi7


回答1:


See this answer as a starting point. We have the same initial three candidates:

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

And the aggregate deduction candidate is based on the actual initializer-list or designated-initializer-list we provide, not the actual underlying members of the aggregate. Our designated-initializer-list is {.second = 20.f} so our aggregate deduction candidate becomes:

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

The template parameters always come from the primary class template, so we bring in the default template arguments from there. The candidate arguments come from the initializer-list, and the type of second is U.

The aggregate deduction 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{.second = 20.f};

Which works, and leads to x.first being initialized from {}.


CTAD for aggregates was only adopted very recently (at the Cologne meeting in July 2019, two months ago). Before that feature, this would still have been well-formed:

my_pair{.second = 20.f};

Why? We don't yet have the aggregate deduction candidate, but we still do have the deduction guide... which is viable. It gives us my_pair<float>. Which is to say, my_pair<float, float> once you fill in the default template argument for U.

That's why gcc is giving you the behavior you see - it simply does not yet implement CTAD for aggregates, and is giving you the old behavior.



来源:https://stackoverflow.com/questions/57886648/ctad-and-designated-initializers-in-c20

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