Due to the aggregate initialization rules, I would expect to be able to initialize d::q by passing an object of its direct base class. However, Clang and MSVC seem to reject this code.
#include <concepts>
template<typename> struct s {};
template<typename> struct b {
template<typename T>
struct p : s<T> {};
};
template<typename U>
struct d : b<U> {
template<typename T>
using t = b<U>::template p<T>;
template<typename T>
struct q : t<T> {};
static constexpr auto v = q{t<U>{}};
};
static_assert(std::same_as<decltype(d<int>::v), d<int>::q<int> const>);
Shouldn't there be some kind of implicit deduction guide generated for d::q that would allow for the construction of q{t<U>{}}? What does the C++20 standard has to say about this? What specific mechanism should kick into action here?
Also, what would be a possible workaround for this issue (constructing d::q with the use of CTAD) that makes the code compile on the latest stable version of all 3 compilers (Clang, GCC, MSVC) without making things overly convoluted? Providing a user-defined deduction guide for d::q seems to work for MSVC but Clang complains about a non-deducible template parameter.
Clang's error message:
<source>:15:31: error: no viable constructor or deduction guide for deduction of
template arguments of 'q'
15 | static constexpr auto v = q{t<U>{}};
| ^
<source>:17:37: note: in instantiation of template class 'd<int>' requested here
17 | static_assert(std::same_as<decltype(d<int>::v), d<int>::q<int> const>);
| ^
<source>:14:12: note: candidate template ignored: could not match 'q' against 'p'
14 | struct q : t<T> {};
| ^
<source>:14:12: note: candidate function template not viable: requires 0 arguments,
but 1 was provided
<source>:17:62: error: expected '(' for function-style cast or type construction
17 | static_assert(std::same_as<decltype(d<int>::v), d<int>::q<int> const>);
| ~~~^
<source>:17:64: error: expected expression
17 | static_assert(std::same_as<decltype(d<int>::v), d<int>::q<int> const>);
|
MSVC's error message:
<source>(15): error C2641: cannot deduce template arguments for 'd<int>::q'
<source>(15): note: the template instantiation context (the oldest one first) is
<source>(17): note: see reference to class template instantiation 'd<int>' being
compiled
<source>(15): error C2780: 'd<U>::q<T> d<int>::q(void)': expects 0 arguments -
1 provided
<source>(14): note: see declaration of 'd<int>::q'
<source>(15): error C2784: 'd<U>::q<T> d<int>::q(d<U>::q<T>)': could not deduce
template argument for 'd<U>::q<T>' from 'b<U>::p<U>'
with
[
U=int
]
<source>(14): note: see declaration of 'd<int>::q'
<source>(15): error C2783: 'd<U>::q<T> d<int>::q(b<<unnamed-symbol>>::p<T>)':
could not deduce template argument for 'T'
<source>(14): note: see declaration of 'd<int>::q'
<source>(15): error C2119: 'v': the type for 'auto' cannot be deduced from an
empty initializer
<source>(17): error C2607: static assertion failed
<source>(17): note: the concept 'std::same_as<const int,const d<int>::q<int>>'
evaluated to false
C:/data/msvc/14.38.33133/include\concepts(35): note: 'const int'
and 'const d<int>::q<int>' are different types
You can default the template parameter for
qas shown below:Now also the program works for all compilers.
Working demo