Olumide
Olumide

Reputation: 5809

Specializing a class template method for derived classes

I'd appreciate help specializing the method doIt() in the following bit of code for classes that share a common base class, as shown below

#include <iostream>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>

struct BarBase {};
struct Bar: BarBase {};

struct FooBase {};
struct Foo: FooBase {};

template <typename T>
struct Task
{
    // I'd like to specialize this method for classes with a common base class
    void doIt();        
};

// my attempt (does not compile)
template <typename T>
typename boost::enable_if<boost::is_base_of<FooBase, T> >::value
doIt() {
    std::cout << "Type is derived from FooBase\n";
}


int main()
{
    Task<Foo> f;
    f.doIt();
}

Upvotes: 0

Views: 458

Answers (2)

Lol4t0
Lol4t0

Reputation: 12547

According to this answer,

SFINAE only works if substitution in argument deduction of a template argument makes the construct ill-formed.

That is why you cannot do smth like that:

template <typename T>
struct Task
{
    typename std::enable_if<std::is_base_of<FooBase, T>::value>::type doIt() {
        std::cout << "Type is derived from FooBase\n";
    }   

    typename std::enable_if<std::is_base_of<FooBase, T>::value == false>::type doIt()
    {
    }
};

Here doIt() isn't template, so no any deduction. But you can do the following:

template <typename T1>
struct Task
{
    template <typename T>
    typename std::enable_if<std::is_base_of<FooBase, T>::value>::type doIt_() {
        std::cout << "Type is derived from FooBase\n";
    }   

    template <typename T>
    typename std::enable_if<std::is_base_of<FooBase, T>::value == false>::type doIt_()
    {
    }

    void doIt()
    {
        doIt_<T1>();
    }
};

Upvotes: 0

AndrzejJ
AndrzejJ

Reputation: 740

You can't specialise a template class member. You can specialise a class, and every specialisation is a complete separate class that inherits nothing from the unspecialised template (it may or may not have all or some of the members of the unspecialised class).

What you can also do is have a template member function in a template class, and specialise that. So you can do this:

template <typename T>
struct Task
{
    void doIt() { doItPriv<T>(); }
private:
    template<typename T1>
    void doItPriv();  
};

and then specialise doItPriv.

Upvotes: 1

Related Questions