Recursive inheritance with variadic templates - c++

Consider the following code:
#include <iostream>
struct ActionOption {
virtual void foo(int) const = 0;
};
template <int> struct ActionType;
template <> struct ActionType<0> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<0>::foo(int) called.\n";}
};
template <> struct ActionType<1> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<1>::foo(int) called.\n";}
};
template <> struct ActionType<2> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<2>::foo(int) called.\n";}
};
template <> struct ActionType<3> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<3>::foo(int) called.\n";}
};
template <> struct ActionType<4> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<4>::foo(int) called.\n";}
};
template <int...> struct PossibleActions;
template <> struct PossibleActions<> { void operator()(int) const {} };
template <int First, int... Rest>
struct PossibleActions<First, Rest...> : ActionType<First>, PossibleActions<Rest...> {
void operator()(int a) const {
ActionType<First>::foo(a);
PossibleActions<Rest...>::operator()(a);
}
};
// Anything that can call ActionType<2>::foo(int) can also call ActionType<3>::foo(int).
struct Object : PossibleActions<1, 2,3, 4> {
void foo(int a) {PossibleActions<1,2,3,4>()(a);}
};
struct Blob : PossibleActions<0, 2,3, 4> {
void foo(int a) {PossibleActions<0,2,3,4>()(a);}
};
int main() {
Object object;
object.foo(12); // ActionType<1>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called
std::cout << std::endl;
Blob blob;
blob.foo(12); // ActionType<0>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called
std::cout << std::endl;
}
It runs except here is the problem: anything that can call ActionType<2>::foo(int) can also call ActionType<3>::foo(int). Thus every time I define a new class, if I use 2 or 3 I have to use both in PossibleActions<I...>. This is problematic for maintenance of course (say I decide in the future that using 2 must also use 3, 7, and 20). The following solution:
using TwoAndThree = PossibleActions<2,3>;
struct Object : PossibleActions<1,4>, TwoAndThree {
void foo(int a) {PossibleActions<1,4>()(a); TwoAndThree()(a);}
};
struct Blob : PossibleActions<0,4>, TwoAndThree {
void foo(int a) {PossibleActions<0,4>()(a); TwoAndThree()(a);}
};
is not acceptable because I need ActionType<N>::foo(int) called in numerical order. Splitting PossibleActions<1,4>()(a); is a very is poor solution too because it runs into the same maintenaince problem (makes maintenance even worse I think).
template <> struct ActionType<2> : ActionOption { virtual void foo(int) const override {std::cout << "ActionType<2>::foo(int) called.\n";} };
template <> struct ActionType<3> : ActionType<2> { virtual void foo(int) const override {std::cout << "ActionType<3>::foo(int) called.\n";} };
does not compile due to ambiguity (and using virtual inheritance did not help), and I can't think of anything else. Is there a solution to this problem?
Perhaps redefine PossibleActions with template <typename... Args> struct PossibleActions;? But then the recursion is lost.
Or is it?
Related question: Is there a way to carry out recursion with Args... where some types are int but some are not (and with those that are not use recursion with the ints that define those types)? For example
PossibleActions<1, TwoAndThree, 4, EightAndTen, 20>()(a);
iterates through 1,2,3,4,8,10,20 as desired because TwoAndThree = PossibleActions<2,3> and EightAndTen = PossibleActions<8,10>??? If possible, that would solve the problem.

Credit goes to Piotr. S for this solution (I wish I could offer him points, but he likes to hide his amazingness for some reason). Though his second solution is nice too, I prefer the syntax offered by his first solution. His Sort struct had to be generalized with
template <typename, typename...> struct Sort;
template <typename T, typename A, typename B>
struct Sort<T,A,B> {
using type = typename Merge<T,A,B>::type;
};
template <typename T, typename First, typename Second, typename... Rest>
struct Sort<T, First, Second, Rest...> {
using type = typename Sort<T, typename Sort<T, First, Second>::type, Rest...>::type;
};
so I did that for him. This allows the syntax
struct Widget : Sort<PossibleActions<0,5>, OneAndFour, TwoAndThree>
which I like better. I added template-templates into the picture too:
#include <iostream>
namespace Detail {
template <typename T, typename, typename, T...> struct Merge;
template <typename T, template <T...> class S, T... Ks>
struct Merge<T, S<>, S<>, Ks...> {
using type = S<Ks...>;
};
template <typename T, template <T...> class S, T... Is, T... Ks>
struct Merge<T, S<Is...>, S<>, Ks...> {
using type = S<Ks..., Is...>;
};
template <typename T, template <T...> class S, T... Js, T... Ks>
struct Merge<T, S<>, S<Js...>, Ks...> {
using type = S<Ks..., Js...>;
};
template <typename T, bool, typename, typename, T...> struct Strip;
template <typename T, template <T...> class S, T I, T... Is, T J, T... Js, T... Ks>
struct Strip<T, true, S<I, Is...>, S<J, Js...>, Ks...> {
using type = Merge<T, S<I, Is...>, S<Js...>, Ks..., J>;
};
template <typename T, template <T...> class S, T I, T... Is, T J, T... Js, T... Ks>
struct Strip<T, false, S<I, Is...>, S<J, Js...>, Ks...> {
using type = Merge<T, S<Is...>, S<J, Js...>, Ks..., I>;
};
template <typename T, template <T...> class S, T I, T... Is, T J, T... Js, T... Ks>
struct Merge<T, S<I, Is...>, S<J, Js...>, Ks...> : Strip<T, (I > J), S<I, Is...>, S<J, Js...>, Ks...>::type {};
template <typename, typename...> struct Sort;
template <typename T, typename A, typename B>
struct Sort<T,A,B> {
using type = typename Merge<T,A,B>::type;
};
// Piotr S.'s Sort generalized to accept any number of template arguments.
template <typename T, typename First, typename Second, typename... Rest>
struct Sort<T, First, Second, Rest...> {
using type = typename Sort<T, typename Sort<T, First, Second>::type, Rest...>::type;
};
}
template <typename... P>
using Sort = typename Detail::Sort<int, P...>::type;
struct ActionOption {
virtual void foo(int) const = 0;
};
template <int> struct ActionType;
template <> struct ActionType<0> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<0>::foo(int) called.\n";}
};
template <> struct ActionType<1> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<1>::foo(int) called.\n";}
};
template <> struct ActionType<2> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<2>::foo(int) called.\n";}
};
template <> struct ActionType<3> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<3>::foo(int) called.\n";}
};
template <> struct ActionType<4> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<4>::foo(int) called.\n";}
};
template <> struct ActionType<5> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<5>::foo(int) called.\n";}
};
template <int...> struct PossibleActions;
template <> struct PossibleActions<> { void operator()(int) const {} };
template <int First, int... Rest>
struct PossibleActions<First, Rest...> : ActionType<First>, PossibleActions<Rest...> {
void operator()(int a) const {
ActionType<First>::foo(a);
PossibleActions<Rest...>::operator()(a);
}
};
using OneAndFour = PossibleActions<1,4>;
using TwoAndThree = PossibleActions<2,3>;
struct Thing : PossibleActions<0,1,2,3,4> {
void foo(int a) {PossibleActions<0,1,2,3,4>::operator()(a);}
};
struct Object : Sort<PossibleActions<1,4>, TwoAndThree> {
void foo(int a) {Sort<PossibleActions<1,4>, TwoAndThree>()(a);}
};
struct Blob : Sort<PossibleActions<0,4>, TwoAndThree> {
void foo(int a) {Sort<PossibleActions<0,4>, TwoAndThree>()(a);}
};
struct Widget : Sort<PossibleActions<0,5>, OneAndFour, TwoAndThree> {
void foo(int a) {Sort<PossibleActions<0,5>, OneAndFour, TwoAndThree>()(a);}
};
int main() {
Thing thing;
thing.foo(12); // ActionType<0>::foo(int) ActionType<1>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called
std::cout << std::endl;
Object object;
object.foo(12); // ActionType<1>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called
std::cout << std::endl;
Blob blob;
blob.foo(12); // ActionType<0>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called
std::cout << std::endl;
Widget widget;
widget.foo(12); // ActionType<0>::foo(int) called ActionType<1>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called ActionType<5>::foo(int) called
}
Note however, the solution actually fails if the original packs are themselves not sorted. This will probably require a helper sorter struct to use first on the original packs before carrying out the above.

Related

C++ conditional template member function

I am trying to understand how to use std::enable_if to choose between 2 functions implementation. In this case, if the type TupleOfCallback doesn't contains all the type, it will not compile because std::get<...> will throw an error.
For exemple:
Executor<Entity1*, Entity2*> task([](Entity1 *e){}, [](Entity2 *2){});
This will not compile because Entity3* is not part of the tuple.
It seem that we can choose between two functions with the same prototype,
void Exec(Entity3 *entity)
{
//enabled when Entity3* is **not** in the tuple
}
OR
void Exec(Entity3 *entity)
{
//enabled when Entity3 is in the tuple
std::get<std::function<void(Entity3*)>>(m_Callbacks)(entity);
}
But i dont understand how to achieve this goal.
C++ template mechanism is still hard for me, any help is welcome.
template<typename ...T>
class Executor
{
typedef std::tuple<std::function<void(T)>...> TupleOfCallback;
public:
Executor(const std::function<void(T)> &...func)
{
}
void Exec(Entity1 *entity)
{
std::get<std::function<void(Entity1*)>>(m_Callbacks)(entity);
}
void Exec(Entity2 *entity)
{
std::get<std::function<void(Entity2*)>>(m_Callbacks)(entity);
}
void Exec(Entity3 *entity)
{
std::get<std::function<void(Entity3*)>>(m_Callbacks)(entity);
}
public:
TupleOfCallback m_Callbacks;
};
Building on this one Check if parameter pack contains a type. You can use two traits to select which method to call:
#include <iostream>
#include <type_traits>
struct Entity1 {};
struct Entity2 {};
struct Entity3 {};
template<typename What, typename ... Args>
struct is_present {
static constexpr bool value {(std::is_same_v<What, Args> || ...)};
};
template<typename T>
struct is_entity : is_present<T,Entity1,Entity2,Entity3> {};
template <typename T, typename ...Args>
struct is_present_entity {
static constexpr bool value = is_present<T,Args...>::value && is_entity<T>::value;
};
template <typename T, typename ...Args>
struct is_not_present_entity {
static constexpr bool value = (!is_present<T,Args...>::value) && is_entity<T>::value;
};
template<typename ...T>
class Executor
{
public:
template <typename U, std::enable_if_t< is_present_entity<U,T...>::value,bool> = true>
void Exec(U* t){
std::cout << "foo\n";
}
template <typename U, std::enable_if_t< is_not_present_entity<U,T...>::value,bool> = true>
void Exec(U* t){
std::cout << "bar\n";
}
};
struct foo {};
int main(void) {
Executor<Entity1,Entity2> ex;
Entity1 e1;
ex.Exec(&e1);
Entity3 e3;
ex.Exec(&e3);
// foo f;
// ex.Exec(&f);
}
output:
foo
bar
Another C++17 option:
template <typename T>
class ExecutorLeaf
{
public:
std::function<void(T)> callback;
void Exec(T entity) { callback(entity); }
};
template <typename... Ts>
class Executor : ExecutorLeaf<Ts>...
{
public:
Executor(const std::function<void(Ts)>&...funcs) : ExecutorLeaf<Ts>{funcs}... {}
using ExecutorLeaf<Ts>::Exec...; // C++17
// Fallback
template <typename T> void Exec(T) {}
};
Demo
If you can guarantee that all types appear only once, then the following should work:
template<typename... Ts>
class Executor {
using TupleOfCallback = std::tuple<std::function<void(Ts)>...>;
public:
Executor(const std::function<void(Ts)>&... func);
template<class E>
std::enable_if_t<(std::is_same_v<Ts, E*> || ...)>
Exec(E* entity) {
std::get<std::function<void(E*)>>(m_Callbacks)(entity);
}
template<class E>
std::enable_if_t<!(std::is_same_v<Ts, E*> || ...)>
Exec(E* entity)
{ }
public:
TupleOfCallback m_Callbacks;
};
The basic idea is to use fold-expression to detect whether E* is included in Ts..., thereby enabling the corresponding function.
Demo.

Multiple template functions with enable_if and is_same and with missing argument list of the class template in C++

I have the following code which compiles nicely:
#include <iostream>
struct Res {};
struct Jac {};
template <typename T, typename S>
class A;
template <typename S>
class A<Res, S>
{
public:
A() { std::cout << "A<Res, S>" << std::endl; }
};
template <typename S>
class A<Jac, S>
{
public:
A() { std::cout << "A<Jac, S>" << std::endl; }
};
template <typename T, typename S>
class B;
template <typename S>
class B<Res, S>
{
public:
B() { std::cout << "B<Res, S>" << std::endl; }
};
template <typename S>
class B<Jac, S>
{
public:
B() { std::cout << "B<Jac, S>" << std::endl; }
};
template<typename S, typename EvalT,
std::enable_if_t<std::is_same<EvalT, A<Res,S>>::value, bool> = true
>
void foo()
{
A<Res, S> a_res;
A<Jac, S> a_jac;
}
template<typename S, typename EvalT,
std::enable_if_t<std::is_same<EvalT, B<Res,S>>::value, bool> = true
>
void foo()
{
B<Res, S> b_res;
B<Jac, S> b_jac;
}
int main() {
foo<int, A<Res,int>>();
foo<int, B<Res,int>>();
return 0;
}
However I am not happy with the calls inside my main() function. I would like them to look like this:
foo<int, A>();
foo<int, B>();
which would imply the following modification of the templates for foo():
template<typename S, typename EvalT,
std::enable_if_t<std::is_same<EvalT, B>::value, bool> = true
>
void foo()
{
B<Res, S> b_res;
B<Jac, S> b_jac;
}
This obviously does not compile. The idea is to have a function, which would instantiate either A or B without explicitly specifying T for my classes because I know that foo() has to create 2 instances with Res and Jac as type parameters. Is there any way to make the code neater and achieve such a behavior?
You can change foo to accept a template template parameter CT that is templated on two types, and enable_if the specific overload based on whether CT<Res, S> is the same type as A<Res, S>, or B<Res, S>:
template<typename S, template<typename, typename> typename CT,
std::enable_if_t<std::is_same<CT<Res,S>, A<Res,S>>::value, bool> = true
>
void foo()
{
A<Res, S> a_res;
A<Jac, S> a_jac;
}
template<typename S, template<typename, typename> typename CT,
std::enable_if_t<std::is_same<CT<Res, S>, B<Res,S>>::value, bool> = true
>
void foo()
{
B<Res, S> b_res;
B<Jac, S> b_jac;
}
Here's a demo.

Template : class specialization

I'm new in the C++ world.
Sorry for my nooby question.
I have a class
template <typename T>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
I want to specialize this template class for 3 types.
If type is (A or B or C), Then use this class
template<>
class Foo<A or B or C>
{
void say_hello()
{ std::cout << "Hello";}
};
What's the best way to do this?
Thank you for your help.
A possible solution uses SFINAE
template <typename T, typename = void>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
template <typename T>
class Foo<T, std::enable_if_t<std::is_same_v<T, A>,
|| std::is_same_v<T, B>,
|| std::is_same_v<T, C>>
{
void say_hello()
{ std::cout << "Hello";}
};
If you don't use T inside the Foo specialization (as in your example) you can also use a sort of self-inheritance
template <typename T>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
template <>
class Foo<A>
{
void say_hello()
{ std::cout << "Hello";}
};
template <>
class Foo<B> : public Foo<A>
{ };
template <>
class Foo<C> : public Foo<A>
{ };
Off Topic: if you want to use say_hello() outside the class, is better if you make it public (or if you declare Foo as a struct).
There are several possibilities, for example:
Specialization of the method only:
template<>
void Foo<A>::say_hello() { std::cout << "Hello"; }
template<>
void Foo<B>::say_hello() { std::cout << "Hello"; }
template<>
void Foo<C>::say_hello() { std::cout << "Hello"; }
or, in C++17, you might do:
template <typename T>
class Foo
{
T t_;
void say_hello()
{
if constexpr(std::is_same_v<T, A> || std::is_same_v<T, B> || std::is_same_v<T, C>) {
std::cout << "Hello";
} else {
std::cout << "Ciao";
}
}
// work with T ...
};
Whereas regular if works in that example, it would fail if you call code specific to A, B, C.
if constexpr won't have that issue.
A variant of the SFINAE solution that is a bit more concise for more classes.
template<class T, class... Ts>
struct is_one_of;
template<class T, class Ts>
struct is_one_of<T, T, Ts...> : std::true_type {}; //maybe add std::decay_t
template<class T, class S, class Ts>
struct is_one_of<T, S, Ts...> : is_one_of<T, Ts...> {};
template<class T>
struct is_one_of<T> : std::false_type{};
template<class T, class... Ts>
constexpr bool is_one_of_v = is_one_of<T, Ts...>::value;
template <typename T, typename = void>
class Foo
{
T t_;
void say_hello()
{ std::cout << "Ciao";}
// work with T ...
};
template <typename T>
class Foo<T, std::enable_if_t<is_one_of_v<T, A, B, C>
{
void say_hello()
{ std::cout << "Hello";}
};

SFINAE and variadic template classes

I'm creating a class C that inherits from variable amount of classes. List of those classes is defined, for example: A,B. In function of class C I need to call functions from all base classes but objects can be C<A,B> , C<A>or C<B> so if I will call functions of class A in C<B> I will get an error. Here is example of the classes and how I've tried to solve problem:
class A
{
int a;
public:
virtual void set_a(const int &value)
{
a = value;
}
protected:
virtual int get_a()
{
return this->a;
}
};
class B
{
int b;
public:
virtual void set_b(const int &value)
{
b = value;
}
protected:
virtual int get_b()
{
return this->b;
}
};
template<class ...T>
struct Has_A
{
template<class U = C<T...>>
static constexpr bool value = std::is_base_of < A, U > ::value;
};
template<class ...T>
class C :
virtual public T...
{
public:
#define HAS_A Has_A<T...>::value
void f()
{
#if HAS_A<>
auto a = this->get_a();
#endif
auto b = this->get_b();
cout << HAS_A<>;
}
};
When I call f() of object C<A,B> it skips the call get_a() but output is true.
Initially, I wrote this
template<class U = C<T...>>
typename std::enable_if<!std::is_base_of<A, U>::value, int>::type get_a()
{
return -1;
}
template<class U = C<T...>>
typename std::enable_if<std::is_base_of<A,U>::value, int>::type get_a()
{
return A::get_a();
}
But I don't want to rewrite this for all functions of A and B. Let's assume that A has 10 more functions.
Is there any beautiful solution?
P.S Sorry for my English. I never used SFINAE before.
Basically I have bunch of genes and I want to write convenient wrap for them where one can configure genes that he wants organism to have.
In current standard, this is trivial:
void f() {
if constexpr(Has_A<T...>::value) {
auto a = get_a();
}
auto b = get_b();
}
If you can use C++17, the bipll's solution (if constexpr ()) is (IMHO) the better one.
Otherwise, C++11 or C++14, I'm not sure it's a good idea but I propose the following solution because it seems to me funny (and a little perverted).
First of all, instead of Has_A I propose a more generic isTypeInList
template <typename...>
struct isTypeInList;
template <typename X>
struct isTypeInList<X> : public std::false_type
{ };
template <typename X, typename ... Ts>
struct isTypeInList<X, X, Ts...> : public std::true_type
{ };
template <typename X, typename T0, typename ... Ts>
struct isTypeInList<X, T0, Ts...> : public isTypeInList<X, Ts...>
{ };
I also propose the use of the simple indexSequence
template <std::size_t...>
struct indexSequence
{ };
that is inspired to std::index_sequence that (unfortunately) is available only starting from C++14.
So, inside C<T...>, you can define the template using
template <typename X>
using list = typename std::conditional<isTypeInList<X, Ts...>{},
indexSequence<0u>,
indexSequence<>>::type;
so that list<A> is indexSequence<0> if A is part of the T... variadic list, indexSequence<> (empty sequence) otherwise.
Now you can write f() that simply call an helper function f_helper() that receive as many indexSequences as many types you need to check.
By example: if you need to know if A and B are part of the T... variadic list, you have to write f() as follows
void f ()
{ f_helper(list<A>{}, list<B>{}); }
Now f_helper() can be a private function and can be
template <std::size_t ... As, std::size_t ... Bs>
void f_helper (indexSequence<As...> const &,
indexSequence<Bs...> const &)
{
using unused = int[];
int a { -1 };
int b { -1 };
(void)unused { 0, ((void)As, a = this->get_a())... };
(void)unused { 0, ((void)Bs, b = this->get_b())... };
// do something with a and b
}
The idea is that As... is 0 if A is in T... or empty list otherwise.
So
int a { -1 };
initialize a with the value of your fake get_a().
With
(void)unused { 0, ((void)As, a = this->get_a())... };
is executed a = this->get_a(), only one time, iff (if and only if) A is in the T... variadic list.
The funny part of this solution is that a = this->get_a() isn't a problem when A isn't in the variadic list. Isn't there if As... is an empty list.
The following is a C++11 full working example (where I've renamed in Ts... the T... variadic sequence for C)
#include <utility>
#include <iostream>
#include <type_traits>
class A
{
private:
int a;
public:
virtual void set_a (int const & value)
{ a = value; }
protected:
virtual int get_a ()
{ std::cout << "get_a()!" << std::endl; return this->a; }
};
class B
{
private:
int b;
public:
virtual void set_b (int const & value)
{ b = value; }
protected:
virtual int get_b ()
{ std::cout << "get_b()!" << std::endl; return this->b; }
};
template <typename...>
struct isTypeInList;
template <typename X>
struct isTypeInList<X> : public std::false_type
{ };
template <typename X, typename ... Ts>
struct isTypeInList<X, X, Ts...> : public std::true_type
{ };
template <typename X, typename T0, typename ... Ts>
struct isTypeInList<X, T0, Ts...> : public isTypeInList<X, Ts...>
{ };
template <std::size_t...>
struct indexSequence
{ };
template <typename ... Ts>
class C : virtual public Ts...
{
private:
template <typename X>
using list = typename std::conditional<isTypeInList<X, Ts...>{},
indexSequence<0u>,
indexSequence<>>::type;
template <std::size_t ... As, std::size_t ... Bs>
void f_helper (indexSequence<As...> const &,
indexSequence<Bs...> const &)
{
using unused = int[];
int a { -1 };
int b { -1 };
(void)unused { 0, ((void)As, a = this->get_a())... };
(void)unused { 0, ((void)Bs, b = this->get_b())... };
// do something with a and b
}
public:
void f ()
{ f_helper(list<A>{}, list<B>{}); }
};
int main()
{
C<> c0;
C<A> ca;
C<B> cb;
C<A, B> cab;
std::cout << "--- c0.f()" << std::endl;
c0.f();
std::cout << "--- ca.f()" << std::endl;
ca.f();
std::cout << "--- cb.f()" << std::endl;
cb.f();
std::cout << "--- cab.f()" << std::endl;
cab.f();
}
I think you can do this with function-member-pointer.
call_if_base calls the given function-pointer only if baseT is the base of T. However all function-results are ignored and it requires at least one parameter.
template <class baseT, class T, typename funcT, class ...Args>
typename std::enable_if<std::is_base_of<baseT, T>::value, void>::type call_if_base(T& obj, funcT func, Args... args) {
(dynamic_cast<baseT&>(obj).*func)(args...);
}
template <class baseT, class T, typename funcT, class ...Args>
typename std::enable_if<!std::is_base_of<baseT, T>::value, void>::type call_if_base(T& obj, funcT func, Args... args) {
}
template<class ...T>
class C :
virtual public T...
{
public:
void set(const int &value) {
call_if_base<A, C>(*this, &A::set_a, 0);
call_if_base<B, C>(*this, &B::set_b, 5);
}
};
or as member-functions
template<class ...T>
class C :
virtual public T...
{
public:
void set(const int &value) {
call_if_base<A>(&A::set_a, 0);
call_if_base<B>(&B::set_b, 5);
}
protected:
template <class baseT, typename funcT, class ...Args>
typename std::enable_if<std::is_base_of<baseT, C>::value, void>::type call_if_base(funcT func, Args... args) {
(dynamic_cast<baseT&>(*this).*func)(args...);
}
template <class baseT, typename funcT, class ...Args>
typename std::enable_if<!std::is_base_of<baseT, C>::value, void>::type call_if_base(funcT func, Args... args) {
}
};

Avoid colliding members in C++ templates

I have a class
template <typename T, typename W>
class A {
void foo(W);
void foo(T);
void foo(int);
}
When T=int, W=int, or W=T, this class fails to compile. How can I get the methods to take priority over each other?
I want the priority W > T > int. So if W=T, foo(T) is ignored and foo(W) is called. If T=int, foo(int) is ignored and foo(T) is called.
The compiler is VS2012, but I have Linux too, and will consider GCC/Clang solutions as well. Anything that compiles on any mainstream compiler goes, but only if you say what compilers it works on.
I would tag dispatch. Override dispatching is easy to understand and scales.
We start with a perfect forwarder:
template<class U> void foo(U&&u){
foo( std::forward<U>(u), std::is_convertible<U, W>{}, std::is_convertible<U,T>{} );
}
it creates tag types, in this case true or false types, to dispatch on.
This one:
void foo( W, std::true_type, ... );
catches everything that can convert to W.
Next, we block this one:
void foo( T, std::false_type, std::true_type );
from considerimg cases where the first argument can convert to W.
Finally, this one:
void foo( int, std::false_type, std::false_type );
can only be considered if the first parameter cannot convert to either.
Fancier tag types, or doing the dispatching one at a time, are both possible.
Sorry for typos.
I use a single C++11 feature -- {} to construct an object -- above. If your compiler lacks support for that C++11 feature, simply upgrade your compiler, it is 2014, get with it. Failing that, replace {} with ().
Use std::enable_if:
#include <type_traits>
template <typename T, typename W>
struct A {
void foo(W) {}
template<typename XT=T> typename std::enable_if<std::is_same<XT,T>::value
&& !std::is_same<T, W>::value, void>::type foo(T) {}
template<typename XT=int> typename std::enable_if<std::is_same<XT,int>::value
&& !std::is_same<int, T>::value
&& !std::is_same<int, W>::value, void>::type foo(int) {}
};
Added for testing:
template struct A<short,char>;
template struct A<char,char>;
template struct A<char,int>;
template struct A<int,char>;
template struct A<int, int>;
struct S {};
int main() {
A<S, int>{}.foo(S{});
}
For the relevant part of your template, you could use speclializations:
template <typename U, typename W>
struct Foo
{
void f(U);
void f(W);
};
template <typename T>
struct Foo<T, T>
{
void f(T);
};
For the rest of your class or class template, you can inherit from Foo<A, B> so you can keep the common code out of the part that needs to be specialized:
template <typename A, typename B>
struct TheClass : Foo<A, B>
{
// common code
};
Try template specializations:
template <typename T, typename W>
class A {
void foo(W);
void foo(T);
void foo(int);
};
template <typename T>
class A<T, T> {
void foo(T);
void foo(int);
};
template <>
class A<int, int> {
void foo(int);
};
Here is a solution without specializations of A, but with two helper structures in a few forms.
#include <iostream>
template<typename T, typename W>
struct T_type { typedef T type; };
template<typename W>
struct T_type<W, W> { typedef void* type; /*dummy type*/};
template<typename T, typename W>
struct int_type { typedef int type; };
template<typename W>
struct int_type<int, W> { typedef void** type; /*dummy type*/};
template<typename T>
struct int_type<T, int> { typedef void** type; /*dummy type*/};
template<>
struct int_type<int, int> { typedef void** type; /*dummy type*/};
template<typename T, typename W>
class A {
public:
void foo(W w) {
std::cout << "foo(W)" << std::endl;
}
void foo(typename T_type<T, W>::type t) {
std::cout << "foo(T)" << std::endl;
}
void foo(typename int_type<T, W>::type i) {
std::cout << "foo(int)" << std::endl;
}
};
int main() {
std::cout << "A<float, char>" << std::endl;
A<float, char> a;
a.foo(1.0f);
a.foo('1');
a.foo(1);
std::cout << "A<float, float>" << std::endl;
A<float, float> b;
b.foo(1.0f);
b.foo(1);
std::cout << "A<int, int>" << std::endl;
A<int, int> c;
c.foo(1);
return 0;
}