Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using decltype in partial template specialization

With the following template and specialization:

template<typename T, typename = void>
struct A {
    void operator()() {
        std::cout << "primary" << std::endl;
    }
};

template<typename T>
struct A<T, decltype(T().f())> {
    void operator()() {
        std::cout << "specialization" << std::endl;
    }
};

used like this:

struct X {
    bool f() { return false; }
};

int main()
{
    A<X>()();
    return 0;
}

the primary template is resolved, when one would expect partial specialisation to be selected. However, when changed to:

template<typename T>
struct A<T, typename std::enable_if<std::is_object<decltype(T().f())>::value>::type> {
    void operator()() {
        std::cout << "specialization" << std::endl;
    }
};

the specialization is chosen. Why isn't specialization chosen in the original example?

like image 216
trozen Avatar asked Jun 05 '26 02:06

trozen


1 Answers

You have instantiated:

A<X>

Which leverages a default template parameter to become:

A<X,void>

Your specialization, however, is:

template<typename T>
struct A<T, decltype(T().f())>

Which, for template parameter X becomes:

struct A<X, decltype(X().f())>

Which is:

struct A<X, bool>

So, your specialization is not the correct choice, because A<X,bool> does not specialize A<X,void>.


If you want your specialization to work for all well-formed instances of T().f(), you can use C++17's std::void_t

std::void_t will evaluate to void for any well-formed template parameters passed to it.

template<typename T>
struct A<T, std::void_t<decltype(T().f())>> {
    void operator()() {
        std::cout << "specialization" << std::endl;
    }
};
like image 171
Drew Dormann Avatar answered Jun 06 '26 18:06

Drew Dormann



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!