9

I would like to have a special formatter for BASECLASS and all derived classes. I have the following classes:

struct BASECLASS { ... };
struct SPECIALFORMAT : BASECLASS { ... }
struct ANOTHERSPECIALFORMAT : BASECLASS { ... }

template <class T>
struct LISTFORMATTER {
  list<T> l;

  bool format() {

  };
}
bool LISTFORMATTER<BASECLASS>::format() { ... }

LISTFORMATTER<BASECLASS> bcFt;
LISTFORMATTER<SPECIALFORMAT> spFt;
LISTFORMATTER<ANOTHERSPECIALFORMAT> aspFt;

bcFt.format(); // <-- ok
spFt.format(); // <-- Calling standard format(), not specialized
aspFt.format(); // <-- Calling standard format(), not specialized

How can I specialize a method for a base class and all inherited classes?

EDIT preferible not using boost. c++ (not c++11)

Miquel
  • 8,339
  • 11
  • 59
  • 82
  • 2
    The similarity, requirements, and potential solution(s) to [this question](http://stackoverflow.com/questions/13580072/specializing-a-class-template-by-a-base-class) are nearly identical, namely specialization-by-base-class. And you're not going to like the answers. – WhozCraig Jan 29 '14 at 17:41
  • For the moment and without an easy fast way to implement is_base_of, I can do it by specifying true or false manually in each declaration. Thanks. – Miquel Jan 29 '14 at 17:54

3 Answers3

7

First, you need is_base_of. If you don't want to use Boost or C++11, then grab one here: How does `is_base_of` work?

Then, you can do this:

template <bool B> struct bool_ {};
// ...
bool format() { do_format(bool_<is_base_of<BASECLASS, T>::value>()); }
bool do_format(bool_<false>) {
  // not inheriting BASECLASS
}
bool do_format(bool_<true>) {
  // inheriting BASECLASS
}

BTW, there is, AFAIK, no way of doing this non-intrusively, i.e. simply by adding a specialization.

Edit: Actually, you can probably do it without is_base_of:

// ...
bool format() { do_format((T*)0); }
bool do_format(void*) { /* not inheriting */ }
bool do_format(BASECLASS*) { /* inheriting */ }

This works because derived->base is a better conversion than class->void.

Community
  • 1
  • 1
Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • Best solution so far IMHO. Thanks Sebastian! – Marco A. Jan 29 '14 at 17:43
  • Good approach but in the linked question I can't find an easy implementation of is_base_of. For the moment the closer approach as @WhozCraig says is in [this question](http://stackoverflow.com/questions/13580072/specializing-a-class-template-by-a-base-class) – Miquel Jan 29 '14 at 17:53
  • This is about as simple as a library-only `is_base_of` gets. Boost's implementation is far more complicated to account for corner cases and compiler bugs. – Sebastian Redl Jan 29 '14 at 18:02
  • I think I found a way without `is_base_of`. – Sebastian Redl Jan 29 '14 at 18:05
  • Thanks @SebastianRedl works like a charm. Very clever. The only thing to take in mind is that it is making an extra stack call, not relevant for my project. – Miquel Jan 30 '14 at 10:56
  • The compiler ought to inline that. – Sebastian Redl Jan 30 '14 at 11:40
2

I think you could do this with enable_if and is_base_of (either from c++11 or boost).

Nathan Monteleone
  • 5,430
  • 29
  • 43
  • Yes, sorry I haven't specified: I preffer not using boost if it is possible (this is by now the only point where it should be needed) and it is c++ – Miquel Jan 29 '14 at 17:22
2

Tag dispatching may help:

struct BASECLASS { };
struct SPECIALFORMAT : BASECLASS { };
struct ANOTHERSPECIALFORMAT : BASECLASS { };

template <typename T>
struct IsDerivedFromBASECLASS {
    static const bool value = false; //std::is_base_of<BASECLASS, T>::value;
};

template <>
struct IsDerivedFromBASECLASS<BASECLASS> { static const bool value = true; };
template <>
struct IsDerivedFromBASECLASS<SPECIALFORMAT> { static const bool value = true; };
template <>
struct IsDerivedFromBASECLASS<ANOTHERSPECIALFORMAT> { static const bool value = true; };


template <class T>
struct LISTFORMATTER {
  //list<T> l;

  bool format();
};

template <typename T, bool IsABASECLASS>
struct helper_format {
    bool operator() (LISTFORMATTER<T>&)
    {
        // default implementation
        return true;
    }
};

template <typename T>
struct helper_format<T, false>
{
    bool operator() (LISTFORMATTER<T>&)
    {
        // specialization implementation
        return false;
    }
};

template<typename T>
bool LISTFORMATTER<T>::format() {
    return helper_format<T, IsDerivedFromBASECLASS<T>::value>(*this);
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302