Replacing switch statements when interfacing between templated and non-templated code - c++

The X:
A common pattern I'm seeing is that the underlying code for a function is templates, but for "reasons" the template code is not available at the upper layer (pick from aversion to templates in interface, the need for a shared library and not to expose implementation to customer, reading type settings at run time instead of compile time, etc.).
This often makes the following:
struct foo { virtual void foo() = 0;}
template <typename T> struct bar : public foo
{
bar( /* Could be lots here */);
virtual void foo() { /* Something complicated, but type specific */}
};
And then an initialize call:
foo* make_foo(int typed_param, /* More parameters */)
{
switch(typed_param)
{
case 1: return new bar<int>(/* More parameters */);
case 2: return new bar<float>(/* More parameters */);
case 3: return new bar<double>(/* More parameters */);
case 4: return new bar<uint8_t>(/* More parameters */);
default: return NULL;
}
}
This is annoying, repetitive, and error prone code.
So I says to myself, self says I, there has GOT to be a better way.
The Y:
I made this. Do you all have a better way?
////////////////////////////////////
//////Code to reuse all over the place
///
template <typename T, T VAL>
struct value_container
{
static constexpr T value() {return VAL;}
};
template <typename J, J VAL, typename... Ts>
struct type_value_pair
{
static constexpr J value() {return VAL;}
template <class FOO>
static auto do_things(const FOO& foo)->decltype(foo.template do_things<Ts...>()) const
{
foo.template do_things<Ts...>();
}
};
template <typename T>
struct error_select
{
T operator()() const { throw std::out_of_range("no match");}
};
template <typename T>
struct default_select
{
T operator()() const { return T();}
};
template <typename S, typename... selectors>
struct type_selector
{
template <typename K, class FOO, typename NOMATCH, typename J=decltype(S::do_things(FOO()))>
static constexpr J select(const K& val, const FOO& foo=FOO(), const NOMATCH& op=NOMATCH())
{
return S::value()==val ? S::do_things(foo) : type_selector<selectors...>::template select<K, FOO, NOMATCH, J>(val, foo, op);
}
};
template <typename S>
struct type_selector<S>
{
template <typename K, class FOO, typename NOMATCH, typename J>
static constexpr J select(const K& val, const FOO& foo=FOO(), const NOMATCH& op=NOMATCH())
{
return S::value()==val ? S::do_things(foo) : op();
}
};
////////////////////////////////////
////// Specific implementation code
class base{public: virtual void foo() = 0;};
template <typename x>
struct derived : public base
{
virtual void foo() {std::cout << "Ima " << typeid(x).name() << std::endl;}
};
struct my_op
{
template<typename T>
base* do_things() const
{
base* ret = new derived<T>();
ret->foo();
return ret;
}
};
int main(int argc, char** argv)
{
while (true)
{
std::cout << "Press a,b, or c" << std::endl;
char key;
std::cin >> key;
base* value = type_selector<
type_value_pair<char, 'a', int>,
type_value_pair<char, 'b', long int>,
type_value_pair<char, 'c', double> >::select(key, my_op(), default_select<base*>());
std::cout << (void*)value << std::endl;
}
/* I am putting this in here for reference. It does the same
thing, but the old way: */
/*
switch(key)
{
case 'a':
{
base* ret = new derived<int>();
ret->foo();
value = ret;
break;
}
case 'b':
{
base* ret = new derived<char>();
ret->foo();
value = ret;
break;
}
case 'c':
{
base* ret = new derived<double>();
ret->foo();
value = ret;
break;
}
default:
return NULL;
}
*/
}
Problems I see with my implementation:
It is clear and readable as mud
Template parameters MUST be types, have to wrap values in types (template <typename T, T VAL> struct value_container { static constexpr T value() {return VAL;} };)
Currently no checking/forcing that the selectors are all type-value pairs.
And the only pros:
Removes code duplication.
If the case statement gets high/the contents of do_things gets high, then we can be a little shorter.
Has anyone do something similar or have a better way?

You can always walk a type list indexed by type_param, as in:
struct foo
{
virtual ~foo() = default;
/* ... */
};
template<typename T>
struct bar : foo
{ /* ... */ };
template<typename TL>
struct foo_maker;
template<template<typename...> class TL, typename T, typename... Ts>
struct foo_maker<TL<T, Ts...>>
{
template<typename... Us>
std::unique_ptr<foo> operator()(int i, Us&&... us) const
{
return i == 1 ?
std::unique_ptr<foo>(new bar<T>(std::forward<Us>(us)...)) :
foo_maker<TL<Ts...>>()(i - 1, std::forward<Us>(us)...); }
};
template<template<typename...> class TL>
struct foo_maker<TL<>>
{
template<typename... Us>
std::unique_ptr<foo> operator()(int, Us&&...) const
{ return nullptr; }
};
template<typename...>
struct types;
template<typename... Us>
std::unique_ptr<foo> make_foo(int typed_param, Us&& us...)
{ return foo_maker<types<int, float, double, uint8_t>>()(typed_param, std::forward<Us>(us)...); };
Note: this factory function is O(n) (although a clever compiler could make it O(1)), while the switch statement version is O(1).

Just to expand YoungJohn's comment, it looks like this (I've included a single initialization of the operator, and it could be made simpler if there was no parameters, but if there are no parameters there is little reason to do this anyway :-P).
#include <functional>
#include <map>
////////////////////////////////////
//////specific impmenetation code
class base{public: virtual void foo() = 0;};
template <typename x>
struct derived : public base
{
virtual void foo() {std::cout << "Ima " << typeid(x).name() << std::endl;}
};
struct my_op
{
int some_param_; /// <shared parameter
my_op(int some_param) : some_param_(some_param){} /// <constructor
template<typename T>
base* do_stuff() const
{
std::cout << "Use some parameter: " << some_param_ << std::endl;
base* ret = new derived<T>();
ret->foo();
return ret;
}
};
base* init_from_params(int some_param, char key)
{
my_op op(some_param);
using factoryFunction = std::function<base*()>;
std::map<char, factoryFunction> mp
{
{ 'a', std::bind(&my_op::do_stuff<int>, &op)},
{ 'b', std::bind(&my_op::do_stuff<long int>, &op)},
{ 'c', std::bind(&my_op::do_stuff<double>, &op)}
} ;
factoryFunction& f = mp[key];
if (f)
{
return f();
}
return NULL;
}
int main(int argc, char** argv)
{
volatile int parameters = 10;
while (true)
{
std::cout << "Press a, b, or c" << std::endl;
char key;
std::cin >> key;
base* value = init_from_params(parameters, key);
std::cout << (void*)value << std::endl;
}
}
Pros: so much shorter, so much more standard, so much less weird template stuff. It also doesn't require the templated arguments to all be types, we can select whatever we want to initialize the function.
Cons: In theory, it could have more overhead. In practice, I totally doubt that the overhead would ever matter.
I like it!

template<class T>
foo* make_foo(int typed_param,/*more params*/)
{
return new bar<T>(/*more params*/);
}

Related

Automatic selection of constructor based on available overloaded versions in Abstract Factory

I am writing an Abstract Factory using C++ templates and was hit by a small obstacle. Namely, a generic class T may provide one or more of the following ways to construct objects:
static T* T::create(int arg);
T(int arg);
T();
I am writing the abstract factory class so that it can automatically try these three potential constructions in the given order:
template <class T>
class Factory {
public:
T* create(int arg) {
return T::create(arg); // first preference
return new T(arg); // this if above does not exist
return new T; // this if above does not exist
// compiler error if none of the three is provided by class T
}
};
How do I achieve this with C++ template? Thank you.
Something along this line should work:
struct S { static auto create(int) { return new S; } };
struct T { T(int) {} };
struct U {};
template<int N> struct tag: tag<N-1> {};
template<> struct tag<0> {};
class Factory {
template<typename C>
auto create(tag<2>, int N) -> decltype(C::create(N)) {
return C::create(N);
}
template<typename C>
auto create(tag<1>, int N) -> decltype(new C{N}) {
return new C{N};
}
template<typename C>
auto create(tag<0>, ...) {
return new C{};
}
public:
template<typename C>
auto create(int N) {
return create<C>(tag<2>{}, N);
}
};
int main() {
Factory factory;
factory.create<S>(0);
factory.create<T>(0);
factory.create<U>(0);
}
It's based on sfinae and tag dispatching techniques.
The basic idea is that you forward the create function of your factory to a set of internal functions. These functions test the features you are looking for in order because of the presence of tag and are discarded if the test fail. Because of sfinae, as long as one of them succeeds, the code compiles and everything works as expected.
Here is a similar solution in C++17:
#include <type_traits>
#include <iostream>
#include <utility>
struct S { static auto create(int) { return new S; } };
struct T { T(int) {} };
struct U {};
template<typename C> constexpr auto has_create(int) -> decltype(C::create(std::declval<int>()), bool{}) { return true; }
template<typename C> constexpr auto has_create(char) { return false; }
struct Factory {
template<typename C>
auto create(int N) {
if constexpr(has_create<C>(0)) {
std::cout << "has create" << std::endl;
return C::create(N);
} else if constexpr(std::is_constructible_v<C, int>) {
std::cout << "has proper constructor" << std::endl;
return new C{N};
} else {
std::cout << "well, do it and shut up" << std::endl;
(void)N;
return C{};
}
}
};
int main() {
Factory factory;
factory.create<S>(0);
factory.create<T>(0);
factory.create<U>(0);
}
Thanks to #StoryTeller and #Jarod42 for the help in this difficult morning.
See it up and running on wandbox.
Okay, thanks to the answer by #skypjack I was able to come up with a more compatible solution that works with pre c++11 compilers. The core idea is the same, i.e. using tag dispatching for ordered testing. Instead of relying on decltype, I used sizeof and a dummy class for SFINAE.
struct S { static auto create(int) { return new S; } };
struct T { T(int) {} };
struct U {};
template<class C, int=sizeof(C::create(0))> struct test_1 { typedef int type; };
template<class C, int=sizeof(C(0))> struct test_2 { typedef int type; };
template<class C, int=sizeof(C())> struct test_3 { typedef int type; };
template<int N> struct priority: priority<N-1> {};
template<> struct priority<0> {};
class Factory {
template<typename C>
C* create(priority<2>, typename test_1<C>::type N) {
return C::create(N);
}
template<typename C>
C* create(priority<1>, typename test_2<C>::type N) {
return new C(N);
}
template<typename C>
C* create(priority<0>, typename test_3<C>::type N) {
return new C();
}
public:
template<typename C>
C* create(int N) {
return create<C>(priority<2>(), N);
}
};
int main() {
Factory factory;
factory.create<S>(0);
factory.create<T>(0);
factory.create<U>(0);
}
Not sure if it is even possible to stuff the sizeof part into the private function signatures; if so, we can get rid of the dummy classes as well.(failed) The slightly ugly part is to use constants (0 in this case) for sizeof operator, which may get tricky if the constructors take arguments of very complicated types.

How to detect whether there is actually a specific member variable in class?

I am purposely using the very same title as this question because I feel that the answer that was accepted does not account for a problem that I am stuck into.
I am looking for a way to detect if some class has some member variable. It is fundamental to note that I am looking for a variable, not a member function or anything else.
Here is the example provided in the question I linked:
template<typename T> struct HasX {
struct Fallback { int x; }; // introduce member name "x"
struct Derived : T, Fallback { };
template<typename C, C> struct ChT;
template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
template<typename C> static char (&f(...))[2];
static bool const value = sizeof(f<Derived>(0)) == 2;
};
struct A { int x; };
struct B { int X; };
int main() {
std::cout << HasX<A>::value << std::endl; // 1
std::cout << HasX<B>::value << std::endl; // 0
}
But we will get the very same output if we do something like
template<typename T> struct HasX {
struct Fallback { int x; }; // introduce member name "x"
struct Derived : T, Fallback { };
template<typename C, C> struct ChT;
template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
template<typename C> static char (&f(...))[2];
static bool const value = sizeof(f<Derived>(0)) == 2;
};
struct A {
void x()
{
}
};
struct B { int X; };
int main() {
std::cout << HasX<A>::value << std::endl; // 1
std::cout << HasX<B>::value << std::endl; // 0
}
(Please note that in the second example the int x in A was substituted with a member function void x()).
I have no real idea on how to work around this problem. I partially fixed this by doing something like
template <bool, typename> class my_helper_class;
template <typename ctype> class my_helper_class <true, ctype>
{
static bool const value = std :: is_member_object_pointer <decltype(&ctype :: x)> :: value;
};
template <typename ctype> class my_helper_class <false, ctype>
{
static bool const value = false;
};
template <typename T> struct HasX
{
// ...
static bool const value = my_helper_class <sizeof(f <Derived>(0)) == 2, T> :: value;
};
Which actually selects if I am using an object. However, the above doesn't work if there are more overloaded functions with the same name x in my class.
For example if I do
struct A
{
void x()
{
}
void x(int)
{
}
};
Then the pointer is not resolved successfully and the a call to HasX <A> doesn't compile.
What am I supposed to do? Is there any workaround or simpler way to get this done?
The problem is that HasX only checks if the name x exists. The ... gets selected if &C::x is ambiguous (which happens if it matches both in Fallback and T). The ChT<> overload gets selected only if &C::x is exactly Fallback::x. At no point are we actually checking the type of T::x - so we never actually check if x is a variable or function or whatever.
The solution is: use C++11 and just check that &T::x is a member object pointer:
template <class T, class = void>
struct HasX
: std::false_type
{ };
template <class T>
struct HasX<T,
std::enable_if_t<
std::is_member_object_pointer<decltype(&T::x)>::value>
>
: std::true_type { };
If &T::x doesn't exist, substitution failure and we fallback to the primary template and get false_type. If &T::x exists but is an overloaded name, substitution failure. If &T::x exists but is a non-overloaded function, substitution failure on enable_if_t<false>. SFINAE for the win.
That works for all of these types:
struct A {
void x()
{
}
void x(int)
{
}
};
struct B { int X; };
struct C { int x; };
struct D { char x; };
int main() {
static_assert(!HasX<A>::value, "!");
static_assert(!HasX<B>::value, "!");
static_assert(HasX<C>::value, "!");
static_assert(HasX<D>::value, "!");
}

Determining which overload was selected

Let's say I have some arbitrary complicated overloaded function:
template <class T> void foo(T&& );
template <class T> void foo(T* );
void foo(int );
I want to know, for a given expression, which foo() gets called. For example, given some macro WHICH_OVERLOAD:
using T = WHICH_OVERLOAD(foo, 0); // T is void(*)(int);
using U = WHICH_OVERLOAD(foo, "hello"); // U is void(*)(const char*);
// etc.
I don't know where I would use such a thing - I'm just curious if it's possible.
Barry, sorry for the misunderstanding in my first answer. In the beginning I understood your question in a wrong way. 'T.C.' is right, that it is not possible except in some rare cases when your functions have different result types depending on the given arguments. In such cases you can even get the pointers of the functions.
#include <string>
#include <vector>
#include <iostream>
//template <class T> T foo(T ) { std::cout << "template" << std::endl; return {}; };
std::string foo(std::string) { std::cout << "string" << std::endl; return {}; };
std::vector<int> foo(std::vector<int>) { std::cout << "vector<int>" << std::endl; return {}; };
char foo(char) { std::cout << "char" << std::endl; return {}; };
template<typename T>
struct Temp
{
using type = T (*) (T);
};
#define GET_OVERLOAD(func,param) static_cast<Temp<decltype(foo(param))>::type>(func);
int main(void)
{
auto fPtr1 = GET_OVERLOAD(foo, 0);
fPtr1({});
auto fPtr2 = GET_OVERLOAD(foo, std::string{"hello"});
fPtr2({});
auto fPtr3 = GET_OVERLOAD(foo, std::initializer_list<char>{});
fPtr3({});
auto fPtr4 = GET_OVERLOAD(foo, std::vector<int>{});
fPtr4({});
auto fPtr5 = GET_OVERLOAD(foo, std::initializer_list<int>{});
fPtr5({});
return 0;
}
The output is:
char
string
string
vector<int>
vector<int>
I'm probably far from what you have in mind, but I've spent my time on that and it's worth to add an answer (maybe a completely wrong one, indeed):
#include<type_traits>
#include<utility>
template <class T> void foo(T&&);
template <class T> void foo(T*);
void foo(int);
template<int N>
struct choice: choice<N+1> { };
template<>
struct choice<3> { };
struct find {
template<typename A>
static constexpr
auto which(A &&a) {
return which(choice<0>{}, std::forward<A>(a));
}
private:
template<typename A>
static constexpr
auto which(choice<2>, A &&) {
// do whatever you want
// here you know what's the invoked function
// it's template<typename T> void foo(T &&)
// I'm returning its type to static_assert it
return &static_cast<void(&)(A&&)>(foo);
}
template<typename A>
static constexpr
auto which(choice<1>, A *) {
// do whatever you want
// here you know what's the invoked function
// it's template<typename T> void foo(T *)
// I'm returning its type to static_assert it
return &static_cast<void(&)(A*)>(foo);
}
template<typename A>
static constexpr
auto
which(choice<0>, A a)
-> std::enable_if_t<not std::is_same<decltype(&static_cast<void(&)(A)>(foo)), decltype(which(choice<1>{}, std::forward<A>(a)))>::value, decltype(&static_cast<void(&)(A)>(foo))>
{
// do whatever you want
// here you know what's the invoked function
// it's void foo(int)
// I'm returning its type to static_assert it
return &foo;
}
};
int main() {
float f = .42;
static_assert(find::which(0) == &static_cast<void(&)(int)>(foo), "!");
static_assert(find::which("hello") == &static_cast<void(&)(const char *)>(foo), "!");
static_assert(find::which(f) == &static_cast<void(&)(float&)>(foo), "!");
static_assert(find::which(.42) == &static_cast<void(&)(double&&)>(foo), "!");
}
I'll delete this answer after a short period during the which I expect experts to curse me. :-)

Select template return type from parameter

I have something working but it seems awfully verbose.
#include <array>
#include <iostream>
#include <type_traits>
using DataArrayShort = std::array<unsigned char, 4>;
using DataArrayLong = std::array<unsigned char, 11>;
// Two base classes the later template stuff should choose between
class Short
{
public:
Short(const DataArrayShort & data) { /* do some init */}
};
class Long
{
public:
Long(const DataArrayLong & data) { /* do some init */}
};
// Concrete derived of the two bases
class S1 : public Short
{
public:
using Short::Short;
operator std::string() { return "S1!";}
};
class S2 : public Short
{
public:
using Short::Short;
operator std::string() { return "S2!";}
};
class L1 : public Long
{
public:
using Long::Long;
operator std::string() { return "L1!";}
};
class L2 : public Long
{
public:
using Long::Long;
operator std::string() { return "L2!";}
};
// Variables that will be modified by parsing other things before calling parse<>()
bool shortDataSet = false;
bool longDataSet = false;
DataArrayShort shortData;
DataArrayLong longData;
// Begin overly verbose template stuff
template<bool IsShort, bool IsLong>
bool getFlag();
template<>
bool getFlag<true, false>()
{
return shortDataSet;
}
template<>
bool getFlag<false, true>()
{
return longDataSet;
}
template<bool IsShort, bool IsLong>
struct RetType
{};
template<>
struct RetType<true, false>
{
typedef DataArrayShort & type;
};
template<>
struct RetType<false, true>
{
typedef DataArrayLong & type;
};
template<bool IsShort, bool IsLong>
typename RetType<IsShort, IsLong>::type getData();
template<>
DataArrayShort & getData<true, false>()
{
return shortData;
}
template<>
DataArrayLong & getData<false, true>()
{
return longData;
}
template<typename T>
inline std::string parse()
{
// First test if I can create the type with initialized data
if (getFlag<std::is_base_of<Short, T>::value, std::is_base_of<Long, T>::value>())
{
// If it's initialized, Then create it with the correct array
T t(getData<std::is_base_of<Short, T>::value, std::is_base_of<Long, T>::value>());
return t;
}
else
{
return "with uninitialized data";
}
}
// End overly verbose template stuff
int main(int argc, const char * argv[])
{
// Something things that may or may not set shortDataSet and longDataSet and give shortData and longData values
std::cout << parse<S1>() << std::endl;
shortDataSet = true;
std::cout << parse<S1>() << std::endl;
std::cout << parse<L2>() << std::endl;
longDataSet = true;
std::cout << parse<L2>() << std::endl;
}
The syntax that's important to me is parse(). Within parse, I want to make sure I route to the correct flag and data to instantiate ConcreteType with.
I'm starting to think I can't use a function template to do what I want - I'm better off using a class template with static function members.
Using std::is_base_of seems clumsy - can I use built-in inheritance with overloads rather than is_base_of with overloads based on Short and Long?
RetType seems unnecessary but there seemed to be no other way to declare getData().
Part of the difficulty is that I need to determine the data to initialize t with before instantiating it.
I don't like the separate template bools for IsShort and IsLong - it won't scale.
What can I do to tighten this up?
You should just forward to a dispatcher that is SFINAE-enabled. Start with an inheritance tree:
template <int I> struct chooser : chooser<I-1> { };
template <> struct chooser<0> { };
Forward to it:
template <typename T>
std::string parse() { return parse_impl<T>(chooser<2>{}); }
And write your cases:
template <typename T,
typename = std::enable_if_t<std::is_base_of<Short, T>::value>
>
std::string parse_impl(chooser<2> ) { // (1)
// we're a Short!
if (shortDataSet) {
return T{shortData};
}
else {
return "with uninitialized data";
}
}
template <typename T,
typename = std::enable_if_t<std::is_base_of<Long, T>::value>
>
std::string parse_impl(chooser<1> ) { // (2)
// we're a Long!
if (longDataSet) {
return T{longData};
}
else {
return "with uninitialized data";
}
}
template <typename >
std::string parse_impl(chooser<0> ) { // (3)
// base case
return "with uninitialized data";
}
If T inherits from Short, (1) is called. Else, if it inherits from Long, (2) is called. Else, (3) is called. This is a handy way to do SFINAE on multiple potentially-overlapping criteria (since you can, after all, inherit from both Short and Long right?)
A little bit of refactoring goes a long way:
template<class T, bool IsShort = std::is_base_of<Short, T>::value,
bool IsLong = std::is_base_of<Long, T>::value>
struct data_traits { };
template<class T>
struct data_traits<T, true, false> {
static bool getFlag() { return shortDataSet; }
static DataArrayShort & getData() { return shortData; }
};
template<class T>
struct data_traits<T, false, true> {
static bool getFlag() { return longDataSet; }
static DataArrayLong & getData() { return longData; }
};
template<typename T>
inline std::string parse()
{
using traits = data_traits<T>;
// First test if I can create the type with initialized data
if (traits::getFlag())
{
// If it's initialized, Then create it with the correct array
T t(traits::getData());
return t;
}
else
{
return "with uninitialized data";
}
}
I can suggest to use traits technique, like other answer. But my solution is better in the way that it allows scability of this solution, I mean no more true, false, ... flags in your code;)
So starting from this comment:
// Variables that will be modified by parsing other things before calling parse<>()
Change your code to more scalable version.
First connect base types with data types:
template <typename BaseType>
class BaseDataTypeTraits;
template <> struct BaseDataTypeTraits<Short>
{
typedef DataArrayShort DataType;
};
template <> struct BaseDataTypeTraits<Long>
{
typedef DataArrayLong DataType;
};
Then define your base type traits:
template <typename BaseType>
struct BaseParseTypeTraits
{
static bool dataSet;
typedef typename BaseDataTypeTraits<BaseType>::DataType DataType;
static DataType data;
};
template <typename BaseType>
bool BaseParseTypeTraits<BaseType>::dataSet = false;
template <typename BaseType>
typename BaseParseTypeTraits<BaseType>::DataType BaseParseTypeTraits<BaseType>::data;
And parse traits for each specific base type:
template <typename T, typename EnableIf = void>
class ParseTypeTraits;
template <typename T>
class ParseTypeTraits<T, typename std::enable_if<std::is_base_of<Short, T>::value>::type>
: public BaseParseTypeTraits<Short>
{};
template <typename T>
class ParseTypeTraits<T, typename std::enable_if<std::is_base_of<Long, T>::value>::type>
: public BaseParseTypeTraits<Long>
{};
And your parse is then almost identical to other "traits" answer:
template<typename T>
inline std::string parse()
{
typedef ParseTypeTraits<T> TTraits;
// First test if I can create the type with initialized data
if (TTraits::dataSet)
{
// If it's initialized, Then create it with the correct array
T t(TTraits::data);
return t;
}
else
{
return "with uninitialized data";
}
}
int main(int argc, const char * argv[])
{
// Something things that may or may not set shortDataSet and longDataSet and give shortData and longData values
std::cout << parse<S1>() << std::endl;
BaseParseTypeTraits<Short>::dataSet = true;
std::cout << parse<S1>() << std::endl;
std::cout << parse<L2>() << std::endl;
BaseParseTypeTraits<Long>::dataSet = true;
std::cout << parse<L2>() << std::endl;
}
Working example: ideone
[UPDATE]
In this example code I also added what is required to add new base and data type.
I mean you have this:
using DataArrayNew = std::array<unsigned char, 200>;
class New
{
public:
New(const DataArrayNew & data) { /* do some init */}
};
class N1 : public New
{
public:
using New::New;
operator std::string() { return "N1!";}
};
And to make these types be supported by your parse - you need only these two specialization:
template <> struct BaseDataTypeTraits<New>
{
typedef DataArrayNew DataType;
};
template <typename T>
class ParseTypeTraits<T, typename std::enable_if<std::is_base_of<New, T>::value>::type>
: public BaseParseTypeTraits<New>
{};
This can be enclosed in a macro:
#define DEFINE_PARSE_TRAITS_TYPE(BaseTypeParam, DataTypeParam) \
template <> struct BaseDataTypeTraits<BaseTypeParam> \
{ \
typedef DataTypeParam DataType; \
}; \
template <typename T> \
class ParseTypeTraits<T, \
typename std::enable_if< \
std::is_base_of<BaseTypeParam, T>::value>::type> \
: public BaseParseTypeTraits<BaseTypeParam> \
{}
So support for new types is as simple as this:
DEFINE_PARSE_TRAITS_TYPE(New, DataArrayNew);
The more simplification can be achieved when we can require that base type has its datatype defined within its class definition - like here:
class New
{
public:
typedef DataArrayNew DataType;
New(const DataArrayNew & data) { /* do some init */}
};
Then we can have generic BaseDataTypeTraits definition:
template <typename BaseType>
struct BaseDataTypeTraits
{
typedef typename BaseType::DataType DataType;
};
So for new type - you only require to add specialization for DataTypeTraits:
template <typename T>
class ParseTypeTraits<T, typename std::enable_if<std::is_base_of<New, T>::value>::type>
: public BaseParseTypeTraits<New>
{};

c++ template specialization for all subclasses

I need to create a template function like this:
template<typename T>
void foo(T a)
{
if (T is a subclass of class Bar)
do this
else
do something else
}
I can also imagine doing it using template specialization ... but I have never seen a template specialization for all subclasses of a superclass. I don't want to repeat specialization code for each subclass
You can do what you want but not how you are trying to do it! You can use std::enable_if together with std::is_base_of:
#include <iostream>
#include <utility>
#include <type_traits>
struct Bar { virtual ~Bar() {} };
struct Foo: Bar {};
struct Faz {};
template <typename T>
typename std::enable_if<std::is_base_of<Bar, T>::value>::type
foo(char const* type, T) {
std::cout << type << " is derived from Bar\n";
}
template <typename T>
typename std::enable_if<!std::is_base_of<Bar, T>::value>::type
foo(char const* type, T) {
std::cout << type << " is NOT derived from Bar\n";
}
int main()
{
foo("Foo", Foo());
foo("Faz", Faz());
}
Since this stuff gets more wide-spread, people have discussed having some sort of static if but so far it hasn't come into existance.
Both std::enable_if and std::is_base_of (declared in <type_traits>) are new in C++2011. If you need to compile with a C++2003 compiler you can either use their implementation from Boost (you need to change the namespace to boost and include "boost/utility.hpp" and "boost/enable_if.hpp" instead of the respective standard headers). Alternatively, if you can't use Boost, both of these class template can be implemented quite easily.
I would use std::is_base_of along with local class as :
#include <type_traits> //you must include this: C++11 solution!
template<typename T>
void foo(T a)
{
struct local
{
static void do_work(T & a, std::true_type const &)
{
//T is derived from Bar
}
static void do_work(T & a, std::false_type const &)
{
//T is not derived from Bar
}
};
local::do_work(a, std::is_base_of<Bar,T>());
}
Please note that std::is_base_of derives from std::integral_constant, so an object of former type can implicitly be converted into an object of latter type, which means std::is_base_of<Bar,T>() will convert into std::true_type or std::false_type depending upon the value of T. Also note that std::true_type and std::false_type are nothing but just typedefs, defined as:
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
I know this question has been answered but nobody mentioned that std::enable_if can be used as a second template parameter like this:
#include <type_traits>
class A {};
class B: public A {};
template<class T, typename std::enable_if<std::is_base_of<A, T>::value, int>::type = 0>
int foo(T t)
{
return 1;
}
I like this clear style:
void foo_detail(T a, const std::true_type&)
{
//do sub-class thing
}
void foo_detail(T a, const std::false_type&)
{
//do else
}
void foo(T a)
{
foo_detail(a, std::is_base_of<Bar, T>::value);
}
The problem is that indeed you cannot do something like this in C++17:
template<T>
struct convert_t {
static auto convert(T t) { /* err: no specialization */ }
}
template<T>
struct convert_t<T> {
// T should be subject to the constraint that it's a subclass of X
}
There are, however, two options to have the compiler select the correct method based on the class hierarchy involving tag dispatching and SFINAE.
Let's start with tag dispatching. The key here is that tag chosen is a pointer type. If B inherits from A, an overload with A* is selected for a value of type B*:
#include <iostream>
#include <type_traits>
struct type_to_convert {
type_to_convert(int i) : i(i) {};
type_to_convert(const type_to_convert&) = delete;
type_to_convert(type_to_convert&&) = delete;
int i;
};
struct X {
X(int i) : i(i) {};
X(const X &) = delete;
X(X &&) = delete;
public:
int i;
};
struct Y : X {
Y(int i) : X{i + 1} {}
};
struct A {};
template<typename>
static auto convert(const type_to_convert &t, int *) {
return t.i;
}
template<typename U>
static auto convert(const type_to_convert &t, X *) {
return U{t.i}; // will instantiate either X or a subtype
}
template<typename>
static auto convert(const type_to_convert &t, A *) {
return 42;
}
template<typename T /* requested type, though not necessarily gotten */>
static auto convert(const type_to_convert &t) {
return convert<T>(t, static_cast<T*>(nullptr));
}
int main() {
std::cout << convert<int>(type_to_convert{5}) << std::endl;
std::cout << convert<X>(type_to_convert{6}).i << std::endl;
std::cout << convert<Y>(type_to_convert{6}).i << std::endl;
std::cout << convert<A>(type_to_convert{-1}) << std::endl;
return 0;
}
Another option is to use SFINAE with enable_if. The key here is that while the snippet in the beginning of the question is invalid, this specialization isn't:
template<T, typename = void>
struct convert_t {
static auto convert(T t) { /* err: no specialization */ }
}
template<T>
struct convert_t<T, void> {
}
So our specializations can keep a fully generic first parameter as long we make sure only one of them is valid at any given point. For this, we need to fashion mutually exclusive conditions. Example:
template<typename T /* requested type, though not necessarily gotten */,
typename = void>
struct convert_t {
static auto convert(const type_to_convert &t) {
static_assert(!sizeof(T), "no conversion");
}
};
template<>
struct convert_t<int> {
static auto convert(const type_to_convert &t) {
return t.i;
}
};
template<typename T>
struct convert_t<T, std::enable_if_t<std::is_base_of_v<X, T>>> {
static auto convert(const type_to_convert &t) {
return T{t.i}; // will instantiate either X or a subtype
}
};
template<typename T>
struct convert_t<T, std::enable_if_t<std::is_base_of_v<A, T>>> {
static auto convert(const type_to_convert &t) {
return 42; // will instantiate either X or a subtype
}
};
template<typename T>
auto convert(const type_to_convert& t) {
return convert_t<T>::convert(t);
}
Note: the specific example in the text of the question can be solved with constexpr, though:
template<typename T>
void foo(T a) {
if constexpr(std::is_base_of_v<Bar, T>)
// do this
else
// do something else
}
If you are allowed to use C++20 concepts, all this becomes almost trivial:
template<typename T> concept IsChildOfX = std::is_base_of<X, T>::value;
// then...
template<IsChildOfX X>
void somefunc( X& x ) {...}