Specialization of the template method for several types

I have a class "A" that provides the template method foo. Foo has a standard implementation that works great 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 the same special implementation for "foo" as D. Is there a way to say something like: For all types, the standard foo is used. For D, E (etc.) 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 thought of using feature classes. But I was hoping there was something simpler to achieve this. Thanks

+4
source share
3 answers

Using Walter Brown (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;
}

Code...

int main(const int argc, const char* argv[argc]) {

  A a;
  B b;
  C c;

  fun(a);
  fun(b);
  fun(c);

  return 0;
}

displays

fun
special fun
special fun

, - , bar() std::is_base_of.

+3

SFINAE,

D E , void bar(), , :

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;

std:: enable_if :

                                   /* 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
}
+2

AFAIK , SFINAE. , type_traits, :

"" enable_if is_same .

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

SFINAE - foo() of class A :

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

PS bonus is that the above solution also works for pre C ++ 11 compilers.

+1
source

Source: https://habr.com/ru/post/1613703/


All Articles