Explicit specializations of specializations of templated members
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Consider the following example, reduced from our [CWG727](https://cplusplus.github.io/CWG/issues/727.html) test (https://godbolt.org/z/b3ej5qWhK):
```cpp
template struct B {
template static const int u = 1; // #1
template<> const int u<0> = 2; // #2, rejected by GCC and Clang 18
};
template<> template const int B<0>::u = 3; // #3, rejected by GCC
static_assert(B<0>().u<0> == 1, "not 1"); // passes in GCC
static_assert(B<0>().u<0> == 2, "not 2"); // passes in Clang 19+ and EDG
static_assert(B<0>().u<0> == 3, "not 3"); // passes in Clang 18 and MSVC
```
Consider a similar example, which adds a specialization of `#3` (https://godbolt.org/z/EbYx55zTG):
```cpp
template struct B {
template static const int u = 1; // #1
template<> const int u<0> = 2; // #2, rejected by GCC
};
template<> template const int B<0>::u = 3; // #3, rejected by GCC
template<> template<> const int B<0>::u<0> = 4; // #4, rejected by Clang 19+
static_assert(B<0>().u<0> == 2, "not 2"); // passes in Clang 19+
static_assert(B<0>().u<0> == 4, "not 4"); // passes in Clang 18, GCC, EDG, and MSVC
```
While Clang 18 was incorrect to reject `#2` in both example in the light of [CWG727](https://cplusplus.github.io/CWG/issues/727.html), I believe it was correctly selecting `#3` and `#4` for static asserts in the first and the second example, respectively.
That is because `#2` is not a specialization of `#3`, i.e. `#3` "hides" `#2`. This is supported by [N4090](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4090.pdf) (prose on page 3, case `a2` in the example after it), which claims to be capturing what Core was converging on. That said, I wasn't able to find minutes of either CWG727 or N4090, so it's an open question how much Core agreed with the paper.
Additionally, I don't believe we are correct to reject `#4` (with a `static data member 'u' already has an initializer` diagnostic) for the same reason we shouldn't be rejecting `#2` — it's a specialization, so it doesn't conflict with the definition of the primary template.
I believe that at least the latter part of this is caused by #93873, so CC @sdkrystian.
Contributor guide
Assessment
This issue has not been assessed yet.