There is disagreement between gcc/clang and msvc when trying to compile the following code:
struct foo {
};
// primary template
template<auto>
struct nttp {
static constexpr int specializaion = 0;
};
// specialization
template<foo f>
struct nttp<f> {
static constexpr int specializaion = 1;
};
int main() {
// Does not compile with msvc 19.30
nttp<5> x{};
}
Full example here.
Msvc is complaining that there is no viable conversion from int to foo which is obviously true, but shouldn't be of any relevance here as far as I understand the rules of partial template specialization.
Quoting cppreference:
When a class or variable (since C++14) template is instantiated, and there are partial specializations available, the compiler has to decide if the primary template is going to be used or one of its partial specializations.
- If only one specialization matches the template arguments, that specialization is used
- If more than one specialization matches, partial order rules are used to determine which specialization is more specialized. The most specialized specialization is used, if it is unique (if it is not unique, the program cannot be compiled)
- If no specializations match, the primary template is used
I'd argue that there is no matching spezialization for int in this case hence the primary template should be selected.
Interestingly, the situation can be fixed by constraining the auto in the specialization by a concept:
template<class T>
concept Foo = std::is_same_v<T, foo>;
template<auto>
struct nttp {
static constexpr int specializaion = 0;
};
template<Foo auto f>
struct nttp<f> {
static constexpr int specializaion = 2;
};
// compiles with all compilers
static_assert(nttp<5>{}.specializaion == 0);
Function templates work as expected, too:
constexpr int test(auto) {
return 0;
}
constexpr int test(foo) {
return 1;
}
// compiles with all compilers
static_assert(test(5) == 0);
Long story short: empirically and intuitively I'd say that this is a bug in MSVC, but as always there's a chance that UB is involved here. So the question would be: are clang/gcc correct, or MSVC, or even all of them?