模板:class 专业化

Template : class specialization

我是 C++ 世界的新手。 抱歉我的新问题。

我有一个class

template <typename T>
class Foo
{
  T t_;
  void say_hello() 
  { std::cout << "Ciao";}
  // work with T ...
};

我想将此模板class专门用于 3 种类型。

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

最好的方法是什么? 谢谢你的帮助。

有几种可能,例如:

仅方法特化:

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

或者,在 C++17 中,您可以这样做:

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

虽然常规 if 在该示例中有效,但如果您调用特定于 ABC 的代码,它将失败。 if constexpr 不会有这个问题。

一种可能的解决方案是使用 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";}
};

如果您不在 Foo 专业化中使用 T(如您的示例所示),您也可以使用一种自我继承

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

题外话:如果你想在 class 之外使用 say_hello(),最好将它设为 public(或者如果你将 Foo 声明为 struct).

SFINAE 解决方案的一个变体,更加简洁类。

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