I am writing something about Partial template specialization.What I want to do is that using a template is_valid to check if the class has a member type named valid. The source code is as below.
#include <iostream>
class A {
public:
typedef void valid;
};
class B {
public:
typedef int valid;
};
class C {
};
template <typename T, typename U = void> struct is_valid
{
const static bool value = false;
};
template <typename T> struct is_valid<T, typename T::valid>
{
const static bool value = true;
};
int main()
{
std::cout << is_valid<A>::value << std::endl;
std::cout << is_valid<B>::value << std::endl;
std::cout << is_valid<C>::value << std::endl;
return 0;
}
However, the output is
1
0
0
The last 0 is clear because C class has no member. But why is in B case, the output is 0?
Can anyone help me to understand what is the mechanism of Partial template specialization here?
For is_valid<B>, the primary template is found, since the 2nd template argument is not specified, the default value void is used, the instantiation is supposed to be is_valid<B, void>. Then specializations get checked. The problem is B::valid is of type int, the instantiation got from specialization would be is_valid<B, int>, which doesn't match the instantiation from the primary template; so the partial specialization won't be selected, the primary template is selected instead.
For is_valid<A>, same as above, the instantiation got from primary template is is_valid<A, void>. Since A::valid is of type void, the partial specialization gives instantiation as is_valid<A, void> too. The specialization is preferred and selected.
If you specify the 2nd template argument as int like is_valid<B, int>, the partial specialization will be selected.
If you just want to check whether the member type valid exists or not, you can use std::void_t which always yielding type void in the partial specialization.
template <typename T> struct is_valid<T, std::void_t<typename T::valid>>
{
const static bool value = true;
};
LIVE
template<typename _T>
struct have_member_valid
{
template<typename T> static std::true_type check(decltype(&T::valid)*);
template<typename T> static std::false_type check(...);
public:
constexpr static bool value = decltype(check<_T>(0))::value;
};
Here is another example to tell whether a class member exists, but I don't quite sure how it works. Maybe param (...) has the lowest priority to match?
Refer: Templated check for the existence of a class member function? (modified a little)
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