1

With a template method, that is specialized for a specific class A, is there a way to call the specialized code for the classes deriving from A ?

The minimal example

#include <iostream<  

class A
{};

class B : public A
{};

class Templator
{
public :
    template <class T>
    void dance(T *argument);
};

template <class T>
void Templator::dance(T *argument)
{
    std::cout << "General implementation" << std::endl;
}

template<>
void Templator::dance<A> (A* )
{
    std::cout << "Specialized implementation" << std::endl;
}

int main()
{
    A a;
    B b;

    Templator tt;
    tt.dance(&a);
    tt.dance(&b);

    return 0;
}

Corresponding output

Specialized implementation
General implementation


In other words, I would like the two outputs to be :

Specialized implementation
Specialized implementation

Ad N
  • 7,930
  • 6
  • 36
  • 80

3 Answers3

3

In C++11 you can use std::enable_if and std::is_base_and_derived:

class Templator{
public :
    template <class T>
    typename std::enable_if<!std::is_base_and_derived<A, T>::value, void>::type 
    dance(T *argument) { 
       std::cout << "General implementation" << std::endl;
    }
    template <class T>
    typename std::enable_if<std::is_base_and_derived<A, T>::value, void>::type 
    dance(T *argument) { 
       std::cout << "Specialized implementation" << std::endl;
    }
};

You can do the same thing in C++03 using either boost::enable_if_c and boost::is_base_of or std::tr1::is_base_of and writing enable_if yourself (see here)

Grizzly
  • 19,595
  • 4
  • 60
  • 78
  • Thank you, I accepted your answer because it was illustrating the use of enable_if and is_base_of (that I obviously was not aware of the existence). And it is solving my specific problem, that's definitely a plus ; ) – Ad N Jan 12 '12 at 17:02
  • I was about to advise you to use `disable_if

    ` instead of `enable_if<!P>`, before realizing it was not included in C++11 (like the original `boost::enable_if` taking a metafunction instead of a boolean)... However, they included the default parameter for the second parameter, so you can omit `void` if you want to avoid some clutter.

    – Luc Touraille Jan 12 '12 at 17:23
  • @LucTouraille: Personally I'd prefer explicitely stating the `void`, since even if it is a default parameter, I think explicitely mentioning the return type is a good idea to make the code clearer. – Grizzly Jan 12 '12 at 17:28
  • Sure, that's a tenable point of view :). I just made this remark for the OP's information. – Luc Touraille Jan 12 '12 at 17:32
1

You just need to cast &b to a A*.

If you change this code

tt.dance(&a);
tt.dance(&b);

To this code

tt.dance(&a);
tt.dance((A*)&b);

The output becomes

Specialized implementation
Specialized implementation
Jack Edmonds
  • 31,931
  • 18
  • 65
  • 77
1

This should be possible using a boost::enable_if in conjunction with boost::is_base_of.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • Yes, it diverges from pure "specialization" to use SFINAE instead... but this is a way to make it work (cf. Lol4t0 pointer under the question) – Ad N Jan 12 '12 at 15:53