Template : class specialization - c++

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";}
};

Related

How to tell if template type is an instance of a non-variadic template class?

This question is awful similar to How to tell if template type is an instance of a template class?
I would like to detect if a template parameter is from one particular template class that has no variadic template arguments.
template<class U, class S>
struct A{};
template<class T>
struct B {
B() {
if constexpr (T == A) {
// T is a template instantiation of `A`.
} else {
}
}
};
I can't change A's definition. I can change B's definition to have additional template parameters.
How do I implement (T == A) given the restriction of not knowing A's U and S?
I would go for a partial specialization here.
#include <iostream>
template<class U, class S>
struct A{};
template<class T>
struct B {
B() {
std::cout << "None-A implementation\n";
}
};
template<class U, class S>
struct B<A<U, S>> {
B() {
std::cout << "A implementation\n";
}
};
int main() {
B<int> b1;
B<A<int, int>> b2;
}
You have the option of leaving the default-case without an implementation.
Or you can have a fallback implementation for any none-A classes like here.
If the partial specialization forces too much code duplication you can also extract the detection part to it's own template variable like this.
#include <iostream>
template<class U, class S>
struct A{};
template <class T>
constexpr bool is_A_instatiation = false;
template <class U, class S>
constexpr bool is_A_instatiation<A<U, S>> = true;
template<class T>
struct B {
B() {
if constexpr (is_A_instatiation<T>) {
std::cout << "A instatiation!\n";
} else {
std::cout << "none-A instatiation!\n";
}
}
};
int main() {
B<int> b1;
B<A<int, int>> b2;
}
The easiest way is:
template<class T>
struct B{/*default implementation*/};
template<class U,class S>
struct B<A<U,S>>{/*Specified implementation*/};
A<T,U>: you already know it and search key
B<...>: variadic types which may include A<T,U> - known type
And you want to search A<T,U> in B<...>
template <typename T, typename U>
struct A {};
template <typename T, typename U, typename ...Ts>
struct B {
static constexpr bool value = ((std::is_same_v< A<T, U>, Ts> || ... ));
};
int main() {
std::cout << std::boolalpha <<
B<int,float, int, int, float, A<int,float>>::value << '\n'<<
B<int,float, int, int, float>::value <<std::endl;
}

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.

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) {
}
};

Specialize template class constructor on templated template parameter

I am trying to find a way to deal with some legacy code. There is a templated class which I would like to specialize the constructor to pass different arguments to its base when instantiated with a certain parameter.
template<typename T, typename U>
class A : public U {
public:
A(T &t, bool b);
// Other member functions
}
template<typename T, typename U>
A<T, U>::A(T &t, bool b)
: U(t, b) {}
I need to change thebehavior of this constructor when U is of a certain (templated) class.
template<typename Z>
class S;
template<typename T>
template<typename Z>
A<T, S<Z>>::A(T &t, bool b)
: S<Z>(t, b, false) {}
Is this possible? I know that class template specializations cannot be done without redefining a new class. But I would rather only specialize this behavior, and not any other member functions of this class U.
A C++11 solution could be based on SFINAE: enabling the first or the second constructor if U is a S based type or not.
To make this, can be useful develop a type traits to detect if a type is (or isn't) S based; by example
template <typename>
struct isS : public std::false_type
{ };
template <typename T>
struct isS<S<T>> : public std::true_type
{ };
With isS, you can write your constructors (in the body of the A class) as follows
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<false == isS<V>::value>::type * = nullptr )
: U(t, b)
{ std::cout << "generic A constructor" << std::endl; }
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<true == isS<V>::value>::type * = nullptr)
: U(t, b, false)
{ std::cout << "S specific A constructor" << std::endl; }
If you need the template argument of S, you can define the specialization of isS as follows
template <typename T>
struct isS<S<T>> : public std::true_type
{ using type = T; };
and use it as typename isS<V>::type.
A full working example
#include <vector>
#include <iostream>
#include <type_traits>
template <typename T>
struct S
{
S (T const &, bool, bool)
{ std::cout << "S constructor" << std::endl; }
};
template <typename>
struct isS : public std::false_type
{ };
template <typename T>
struct isS<S<T>> : public std::true_type
{ };
template <typename T, typename U>
struct A : public U
{
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<false == isS<V>::value>::type * = nullptr )
: U(t, b)
{ std::cout << "generic A constructor" << std::endl; }
template <typename V = U>
A(T & t, bool b,
typename std::enable_if<true == isS<V>::value>::type * = nullptr)
: U(t, b, false)
{ std::cout << "S specific A constructor" << std::endl; }
};
int main ()
{
long l { 0L };
// print "generic A constructor"
A<long, std::vector<int>> alv(l, true);
// print "S constructor>" and "S specific A constructor"
A<long, S<int>> als(l, true);
}
You can add a function called id to each of your classes, with each class' id function returning a different value. You can then what was returned by a type's id function when it is passed in.
If you don't want to specialize this class, you can specialize one you'd inherit:
template<typename T, typename U>
class A_impl : public U {
public:
A_impl(T &t, bool b) : U(t, b) { }
};
template<typename T, typename Z>
class A_impl<T,S<Z> > : public S<Z> {
public:
A_impl(T &t, bool b) : S<Z>(t, b, false) { }
};
template<typename T, typename U>
class A : public A_impl<T,U> {
public:
using A_impl<T,U>::A_impl; // C++11 : inherit A_impl's constructor here
A(T &t, bool b) : A_impl<T,U>(t, b) {} // or C++98 calling it
};

Template method specialization for multiple types

I have a class “A” which exposes the template method foo.
Foo has a standard implementation which works fine with B,C. It also has a special implementation for D.
class A
{
template<typename T>
void foo()
{
//standard implementation
}
template<>
void foo<D>
{
//special implementation
}
}
class B{};
class C{};
class D{};
int main()
{
A<B> a1;
A<C> a2;
A<D> a3;
}
Now, I need to add the class E, which requires for "foo" the same special implementation as D.
Is there a way to say something like: For all the types use the standard foo. For D,E (and so on) the special implementation.
class A
{
template<typename T>
void foo()
{
//standard implementation
}
template<>
void foo<D && E> <-- PseudoCode - It doesn't work
{
//special implementation
}
}
class B{};
class C{};
class D{};
class E{};
int main()
{
A<B> a1;
A<C> a2;
A<D> a3;
A<E> a4;
}
I was thinking to use the trait classes. But I was hoping there is something simpler to achieve this.
Thanks
Using Walter Brown's (C++1z) void_t.
#include <iostream>
#include <type_traits>
template <typename...>
using void_t = void;
template <typename T, typename = void>
struct has_bar
: std::false_type { };
template <typename T>
struct has_bar<T, void_t<decltype( std::declval<T&>().bar() ) > >
: std::true_type { };
class A {
public:
void foo() { };
};
class B {
public:
void bar() { };
};
class C {
public:
void bar() { };
};
template <typename T>
typename std::enable_if<!has_bar<T>::value, void>::type
fun(T t) {
std::cout << "fun" << std::endl;
}
template <typename T>
typename std::enable_if<has_bar<T>::value, void>::type
fun(T t) {
std::cout << "special fun" << std::endl;
}
The code...
int main(const int argc, const char* argv[argc]) {
A a;
B b;
C c;
fun(a);
fun(b);
fun(c);
return 0;
}
prints out
fun
special fun
special fun
Note, that does not check any type semantics, so it may be better declaring bar() as an interface and using std::is_base_of.
You should take a look on SFINAE to enable and disable function at compile time
If D and E are special, they have let's say the member void bar() and not the others, you can actually implement your own type trait:
template<typename T>
struct has_bar {
private:
template<typename C> static std::true_type test(decltype(&C::bar)*);
template<typename C> static std::false_type test(...);
public:
constexpr static bool value = decltype(test<T>(nullptr))::value;
};
/* false */ /* true */
cout << boolalpha << has_bar<A> << " " << has_bar<E> << endl;
Now with this type trait you can use std::enable_if as a compile time switch:
/* standard if no bar */
template<typename T, typename = enable_if_t< !has_bar<T> >>
void foo()
{
//standard implementation
}
/* special if bar */
template<<typename T, typename = enable_if_t< has_bar<T> >>
void foo()
{
//special implementation
}
AFAIK there's no way you can do this without defining some SFINAE machinery. Now the minimum I can think of without including type_traits header would be the following:
Define "home made "enable_if and is_same type traits as follows.
namespace mine {
template<bool, typename T = void> struct enable_if {};
template<typename T> struct enable_if<true, T> { typedef T type; };
template<typename T, typename U> struct is_same { static bool const value = false; };
template<typename T> struct is_same<T, T> { static bool const value = true; };
};
Apply SFINAE in member function foo() of class A as follows:
class A {
template<typename T>
struct pred {
static bool const value = mine::is_same<T, B>::value ||
mine::is_same<T, C>::value || mine::is_same<T, D>::value || mine::is_same<T, E>::value;
};
public:
template<typename T>
typename mine::enable_if< pred<T>::value, void>::type
foo() { std::cout << "special implementation" << std::endl; }
template<typename T>
typename mine::enable_if<!pred<T>::value, void>::type
foo() {std::cout << "standard implementation" << std::endl; }
};
LIVE DEMO
P.S the bonus is that the above solution works also for pre C++11 compilers.