Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ Partial template specialization with typename as void

Tags:

c++

templates

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?

like image 951
irasin Avatar asked Oct 24 '25 09:10

irasin


2 Answers

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

like image 181
songyuanyao Avatar answered Oct 27 '25 00:10

songyuanyao


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)

like image 26
wwc Avatar answered Oct 27 '25 00:10

wwc