Шаблон: специализация класса - PullRequest
2 голосов
/ 19 марта 2020

Я новичок в мире C ++. Извините за вопрос nooby.

У меня есть класс

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

Я хочу специализировать этот шаблонный класс для 3 типов.

Если тип (A или B или C), затем используйте этот класс

template<>
class Foo<A or B or C>
{
  void say_hello() 
  { std::cout << "Hello";}
};

Какой лучший способ сделать это? Спасибо за вашу помощь.

Ответы [ 3 ]

4 голосов
/ 19 марта 2020

Возможное решение использует 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";}
};

Если вы не используете T внутри специализации Foo (как в вашем примере), вы также можете использовать своего рода самонаследование

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 Topi c: если вы хотите использовать say_hello() вне класса, лучше, если вы сделаете его public (или если вы объявите Foo как struct).

3 голосов
/ 19 марта 2020

Есть несколько возможностей, например:

Специализация только метода:

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 работает в этом примере, он потерпит неудачу, если вы вызовете код с указанием c на A, B, C. if constexpr такой проблемы не будет.

0 голосов
/ 19 марта 2020

Вариант решения 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";}
};
...