C ++, применять шаблон шаблона для избирательного функционирования - PullRequest
1 голос
/ 04 октября 2019

У меня есть класс, который может быть создан с помощью аргументов «обычных» типов, int, string и т. Д., Или который может быть создан с помощью пары различных «специальных» типов, изобретенных коллегой.

«Специальные» типы имеют одну и ту же сигнатуру, но не находятся в отношениях «родитель-потомок».

Итак, мой код выглядит примерно так:

class my_nifty_class {
  public:
  // "ordinary" constructor
  template <class T> my_nifty_class(T) {some generic code}

  // "special" constructors
  my_nifty_class(my_first_clever_class) {
    some clever code
  }
  my_nifty_class(my_second_clever_class) {
    the identical clever code
  }

В порядкечтобы не дублировать какой-нибудь умный код (и не подвергаться риску не всегда дублировать его правильно), я хотел бы заменить это на

class my_nifty_class {
  public:
  // "ordinary" constructor
  template <class T> my_nifty_class(T) {some generic code}

  // "special" constructors
  template <class clever_class> my_nifty_class(clever_class) {
    /**** I need template magic somewhere around here ****/
    some clever code
  }

Но - я не знаю, какое волшебство шаблонаположить туда, или если есть такая магия, которая будет иметься. Я знаю, что мог бы сделать это, если бы объявлял классы - но я объявлял функции, так что я немного застрял.

Ответы [ 3 ]

3 голосов
/ 04 октября 2019

Вы хотите std::enable_if, и вам нужно какое-то свойство времени компиляции ваших специальных классов, которого нет у других классов.

template <class T, class S = std::enable_if_t<!is_my_special_v<T>>>
my_nifty_class(T) {some generic code}

template <class T, class S = std::enable_if_t<is_my_special_v<T>>, bool = true>
my_nifty_class(T) {some special code}

(Для создания двух шаблонов необходим фиктивный параметр шаблонаотлично)

Другой метод - иметь только один конструктор и использовать специальный селектор внутри.

template <class T>
my_nifty_class(T) {
   if constexpr(is_my_special_v<T>)
     some special code
   else
     some generic code
}

Как вы пишете is_my_special_v? Это просто шаблон со значением false, со специализациями для ваших специальных типов со значением true.

template<class> constexpr bool is_my_special_v = false;
template<> constexpr bool is_my_special_v<MySpecialType1> = true:
// ...

Если все ваши специальные классы имеют какое-то имя члена, которое вряд ли встречается в неспециальныхклассы, вы можете использовать это для того, чтобы записать только одну специализацию итого is_my_special_v вместо одной для каждого специального класса. Ищите «обнаружение членов c ++», много материала там.

Наконец, если это единственное место, где ваши специальные типы действительно особенные, вы можете вообще пропустить is_my_special_v и просто проверить прямо.

template <class T>
my_nifty_class(T) {
   if constexpr(std::is_same_v<T, MySpecialType1> ||
         std::is_same_v<T, MySpecialType2> ...)
     some special code
   else
     some generic code
}
0 голосов
/ 04 октября 2019

Вот мой ответ. Вы просто поделитесь универсальным конструктором для всех типов. И обрабатывать логику в конструкторе, используя std::is_pod, который был введен в c ++ 11. Я считаю, что

По существу POD (простые старые данные) типы, такие как;int, float, double и т. д. будут обрабатываться одной шаблонной функцией, а любые сложные / нетривиальные типы данных будут обрабатываться другой шаблонной функцией.

class my_nifty_class {
  public:
  template<class T> handle_pod_type(T value)
  { /* Code to handle POD data types */ }

  template<class SpecialType> handle_special_type(SpecialType value)
  { /* Code to handle complex data types */ }

  template <class T> my_nifty_class(T value) {
     if( std::is_pod<T>::value ) {
        handle_pod_type(value);
     }
     else {
        handle_special_type(value);
     }
  }

}

Также обратите внимание на то, что is_pod что делает и что классифицирует тип POD в C ++ 11.

0 голосов
/ 04 октября 2019

Я предлагаю вам использовать "структуры тегов" и специализации шаблонов классов для решения вашей проблемы:

struct TypeA {};
struct TypeB {};
struct TypeC {};

class Class {
public:
    template<class T> Class(T val) : Class(typename SelectTag<T>::Type{}, val) {}

private:
    struct GenericTag {};
    struct BOrCTag {};

    template<class T> struct SelectTag { using Type = GenericTag; };


    template<class T> Class(GenericTag, T val) { /* do smth */ }
    template<class T> Class(BOrCTag, T val) { /* do smth else */ }
};

template<> struct Class::SelectTag<TypeB> { using Type = BOrCTag; };

template<> struct Class::SelectTag<TypeC> { using Type = BOrCTag; };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...