Is the following code in accordance with the C++20 standard? Or, should it be rejected due to some syntax error? All 3 compilers (Clang, GCC, and MSVC) seem to reject it.
template<typename...>
struct n {
template<typename>
struct b {
template<typename>
struct p {};
};
template<typename T>
struct d : b<T>::template p<T> {};
template<typename T>
d(b<int>::template p<T>) -> d<T>;
template<typename T>
static constexpr auto v = d{b<int>::template p<T>{}};
};
inline constexpr auto w = n{}.v<int>;
When removing the template-head of type n, all compilers accept the code. Why does this matter? What does the standard have to say about the way the code should be processed based on whether n is templated?
Clang's error message:
<source>:11:15: error: 'template' keyword not permitted here
11 | d(b<int>::template p<T>) -> d<T>;
| ^~~~~~~~
<source>:11:24: error: member 'p' declared as a template
10 | template<typename T>
| ~~~~~~~~~~~~~~~~~~~~
11 | d(b<int>::template p<T>) -> d<T>;
| ^
<source>:11:29: error: expected ';' at end of declaration list
11 | d(b<int>::template p<T>) -> d<T>;
| ^
| ;
<source>:13:54: error: expected '}'
13 | static constexpr auto v = d{b<int>::template p<T>{}};
| ^
<source>:13:32: note: to match this '{'
13 | static constexpr auto v = d{b<int>::template p<T>{}};
| ^
<source>:13:27: error: declaration of variable 'v' with deduced type
'const auto' requires an initializer
13 | static constexpr auto v = d{b<int>::template p<T>{}};
| ^
<source>:13:27: error: declaration of variable 'v' with deduced type
'const auto' requires an initializer
<source>:15:31: note: in instantiation of static data member 'n<>::v<int>'
requested here
15 | inline constexpr auto w = n{}.v<int>;
| ^
<source>:15:23: error: constexpr variable 'w' must be initialized by a
constant expression
15 | inline constexpr auto w = n{}.v<int>;
| ^ ~~~~~~~~~~
<source>:15:27: note: non-literal type 'auto' cannot be used in a constant
expression
15 | inline constexpr auto w = n{}.v<int>;
| ^
GCC's error message:
<source>:13:32: error: missing template arguments before '{' token
13 | static constexpr auto v = d{b<int>::template p<T>{}};
| ^
<source>:15:31: error: 'struct n<>' has no member named 'v'
15 | inline constexpr auto w = n{}.v<int>;
| ^
<source>:15:33: error: expected primary-expression before 'int'
15 | inline constexpr auto w = n{}.v<int>;
| ^~~
MSVC's error message:
<source>(13): error C2760: syntax error: '{' was unexpected here; expected '}'
<source>(13): note: the template instantiation context (the oldest one first) is
<source>(14): note: see reference to class template instantiation
'n<<unnamed-symbol>...>' being compiled
As mentioned by HolyBlackCat, adding typename to b<int>::template p<T>{} makes the construction of d possible on GCC and MSVC. Clang still rejects the code because it seems to have an issue with the deduction guide, however.
This leaves me with the question whether typename can be omitted from d's deduction guide while still being compliant to the C++20 standard. MSVC also allows the omittance of typename when changing the curley braces to parentheses, but I presume this behavior to be non-compliant.
typename. Looks like the deduction guide parameters aren't there.