partial template specialization for all derived classes

C

Christof Warlich

Hi,

I just learned and played around a bit with partial template
specialization, e.g. specializing for all pointers:

#include <iostream>
template<typename T> class MyClass {
public:
void someMember() {
std::cout << "No pointer.\n";
}
};
template<typename T> class MyClass<T *> {
public:
void someMember() {
std::cout << "Pointer.\n";
}
};
int main(void) {
MyClass<int *> pointer1;
MyClass<char *> pointer2;
MyClass<int> noPointer;
pointer1.someMember();
pointer2.someMember();
noPointer.someMember();
}

But what I really need is a partial specialization for a specific base
class and all its derived classes, i.e. something like:

#include <iostream>
class Base {};
class Derived: public Base {};
class Any {};
template<typename T> class MyClass {
public:
void someMember() {
std::cout << "Anything else.\n";
}
};
template<typename T> class MyClass<T: public Base> { // fantasy syntax
public:
void someMember() {
std::cout << "Class Base or any derived class of Base.\n";
}
};
int main(void) {
MyClass<Base> base;
MyClass<Derived> derived;
MyClass<Any> any;
base.someMember();
derived.someMember();
any.someMember();
}

Is there any way to achieve something like this?

Thanks for any help,

Christof
 
J

Jeff Schwab

Christof said:
Hi,

I just learned and played around a bit with partial template
specialization, e.g. specializing for all pointers:

#include <iostream>
template<typename T> class MyClass {
public:
void someMember() {
std::cout << "No pointer.\n";
}
};
template<typename T> class MyClass<T *> {
public:
void someMember() {
std::cout << "Pointer.\n";
}
};
int main(void) {
MyClass<int *> pointer1;
MyClass<char *> pointer2;
MyClass<int> noPointer;
pointer1.someMember();
pointer2.someMember();
noPointer.someMember();
}

But what I really need is a partial specialization for a specific base
class and all its derived classes, i.e. something like:

#include <iostream>
class Base {};
class Derived: public Base {};
class Any {};
template<typename T> class MyClass {
public:
void someMember() {
std::cout << "Anything else.\n";
}
};
template<typename T> class MyClass<T: public Base> { // fantasy syntax
public:
void someMember() {
std::cout << "Class Base or any derived class of Base.\n";
}
};
int main(void) {
MyClass<Base> base;
MyClass<Derived> derived;
MyClass<Any> any;
base.someMember();
derived.someMember();
any.someMember();
}

Is there any way to achieve something like this?

Use a boolean test like boost::is_base_of to get a bool. Use the bool
as an argument to a separate template, which you may specialize for
either the true or false case.

http://www.boost.org/doc/html/boost_typetraits/reference.html#boost_typetraits.is_base_of
 
J

Jeff Schwab

Jeff said:
Use a boolean test like boost::is_base_of to get a bool. Use the bool
as an argument to a separate template, which you may specialize for
either the true or false case.

http://www.boost.org/doc/html/boost_typetraits/reference.html#boost_typetraits.is_base_of

I just realized is_base_of is in tr1. (And there was much rejoicing.)

#include <iostream>
#include <tr1/type_traits>

struct base { };
struct derived: base { };
struct any { };

template<bool is_subclass>
struct my_class_impl {
void some_member() const {
std::cout << "Anything else.\n";
}
};

template<>
struct my_class_impl<true> {
void some_member() const {
std::cout << "Class base or subclass of base.\n";
}
};

template<typename T>
struct my_class:
my_class_impl<std::tr1::is_base_of<base, T>::value > { };

int main() {
my_class<base>().some_member();
my_class<derived>().some_member();
my_class<any>().some_member();
}
 
B

Barry

I just realized is_base_of is in tr1. (And there was much rejoicing.)

#include <iostream>
#include <tr1/type_traits>

struct base { };
struct derived: base { };
struct any { };

template<bool is_subclass>
struct my_class_impl {
void some_member() const {
std::cout << "Anything else.\n";
}

};

template<>
struct my_class_impl<true> {
void some_member() const {
std::cout << "Class base or subclass of base.\n";
}

};

template<typename T>
struct my_class:
my_class_impl<std::tr1::is_base_of<base, T>::value > { };

int main() {
my_class<base>().some_member();
my_class<derived>().some_member();
my_class<any>().some_member();

Just a nit,
Introducing a default template argument could eliminate the
inheretance,
making it the way the OP did.

template <class T, bool B = std::tr1::is_base_of<Base> >
struct MyClass {
// false
};

template <class T, true>
struct MyClass {
// true
};
 
B

Barry

Just a nit,
Introducing a default template argument could eliminate the
inheretance,
making it the way the OP did.

template <class T, bool B = std::tr1::is_base_of<Base> >
struct MyClass {
// false

};

template <class T, true>
struct MyClass {
// true



};

Oops,

template <class T>
struct MyClass<T, true> {
};
 
J

Jeff Schwab

Not a nit at all. You have entirely obviated the need for the _impl
class. Nicely done!
 
C

Christof Warlich

Jeff said:
I just realized is_base_of is in tr1. (And there was much rejoicing.)

#include <iostream>
#include <tr1/type_traits>

struct base { };
struct derived: base { };
struct any { };

template<bool is_subclass>
struct my_class_impl {
void some_member() const {
std::cout << "Anything else.\n";
}
};

template<>
struct my_class_impl<true> {
void some_member() const {
std::cout << "Class base or subclass of base.\n";
}
};

template<typename T>
struct my_class:
my_class_impl<std::tr1::is_base_of<base, T>::value > { };

int main() {
my_class<base>().some_member();
my_class<derived>().some_member();
my_class<any>().some_member();
}

Hi Jeff,

thanks a lot for this, it's exactly what I was looking for, but after a
day of trying myself I wouldn't have bet a penny that this is possible.
Looks like there is still quite a bit to learn.

Cheers,

Christof
 
C

Christof Warlich

Ok, so to sum up this would be something like this (using Boosts
is_convertible instead of TR1 is_base_of):

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

struct base { };
struct derived: base { };
struct any { };

template<typename T, bool is_subclass = boost::is_convertible<T,
base>::value> struct my_class {
void some_member() const {
std::cout << "Anything else.\n";
}
};
template<typename T> struct my_class<T, true> {
void some_member() const {
std::cout << "Class base or subclass of base.\n";
}
};

int main() {
my_class<base>().some_member();
my_class<derived>().some_member();
my_class<any>().some_member();
}

Again, many thanks!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,739
Latest member
Clint8040

Latest Threads

Top