I came across this issue while trying to specialize tuple_size
/tuple_element
for a custom class in C++17 for structured binding.
Below code compiles in GCC, but not in clang (both trunk versions, see below link).
#include <type_traits>
template<typename T, typename... Ts>
using sfinae_t = T;
template<typename T, bool... Bs>
using sfinae_v_t = sfinae_t<T, typename std::enable_if<Bs>::type...>;
template <typename T>
struct Test;
template <typename T>
struct Test<sfinae_v_t<T, std::is_integral_v<T>>> {};
void f() {
Test<int> t;
}
https://godbolt.org/z/ztuRSq
This is the error provided by clang:
<source>:13:8: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list
struct Test<sfinae_v_t<T, std::is_integral<T>::value>> {};
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Compiler returned: 1
Is this is a bug in either compiler or does above code invokes some UB?
What I tell below (under OLD POST) should be true to a degree, but the actual problem with this is, that SFINAE is used wrongly, hence I am not that sure anymore that this is a bug in gcc.
An alias declaration must always succeed, you cannot SFINAE there, since it is not a class or function declaration or specializations (that makes sense, since you cannot specialize aliases). If the alias declaration does not succeed, the programm is ill-formed. Hence the compiler may assume that it will never come to the case that the alias declaration does not succeed until you force it to instantiate such a template.
Hence it is perfectly acceptable for the compiler to think that sfinae_v_t<T,...>
is always T
, since that will happen, when the programm is not ill-formed. Hence it will see, that in all cases in which the programm is not ill-formed, the partial specialization does not specialize and as such it will tell you that this is ill-formed. (That is what clang does).
I don't think that the compiler is forced to do this. And if it does not, and just thinks "Ok, sfinae_v_t
is some type, whatever.", then it is not obvious that this a redeclaration. So I think until we instantiate one of them there is nothing wrong with not throwing an error.
But when we instantiate it there should be either the problem that we have a redeclaration or that the program is ill-formed due to std::enable_if
, depending on the template argument. GCC should pick up at least one of them but does neither.
This also does absolutely not apply to the more easy example without std::enable_if
. So I still think this is a bug in GCC, but I am sufficiently mindfucked that I cannot say that with certainity anymore. I would just say, someone should report that as a bug and let the people from gcc think about it.
OLD POST
This is a bug in gcc. The standard gives us rules for converting a class template in function templates. One class template is more specialized than another if its function comes before the other's in the partial function template ordering.
I created the functions here and now gcc claims that calling them is ambiguous, hence it would also have to say that the class templates are equally specified.
Note: Reading the standard carefully, the compiler in my head agrees with clang.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With