Как мы можем позволить классу шаблона, указанному enum в качестве аргумента шаблона, иметь общую функцию? - PullRequest
2 голосов
/ 26 марта 2020

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

#include <iostream>                                                                                    

enum E{
  E1, 
  E2  
};

template <enum E>
class X { 
  public:
  void f_common() {
   std::cout << "common" << std::endl;
  }
};

template <>
class X<E::E1> {
  public:
  void f() {
   std::cout << "E1" << std::endl;
  }
};

template <>
class X<E::E2> {
  public:
  void f() {
   std::cout << "E2" << std::endl;
  }
};


int main() {
  X<E::E1> e1; 
  X<E::E2> e2; 

  e1.f(); // "E1" is shown
  e2.f(); // "E2" is shown

  e1.f_common();// compile error
  e2.f_common();// compile error

  return 0;
}

Ответы [ 2 ]

2 голосов
/ 26 марта 2020

Различные специализации не связаны друг с другом

Есть несколько способов исправить ваш код (без повторения общего кода):

  • использовать базовый класс

    class X_common { 
    public:
      void f_common() const { std::cout << "common" << std::endl; }
    };
    
    template <E> class X;
    
    template <>
    class X<E::E1> : X_common {
    public:
      void f() const { std::cout << "E1" << std::endl; }
    };
    template <>
    class X<E::E2> : X_common {
    public:
      void f() const { std::cout << "E2" << std::endl; }
    };
    
  • полностью специализированный метод

    template <E> class X
    { 
    public:
        void f_common() const { std::cout << "common" << std::endl; }
        void f() const;
    };
    
    template <>
    void X<E::E1>::f() const { std::cout << "E1" << std::endl; }
    template <>
    void X<E::E2>::f() const { std::cout << "E2" << std::endl; }
    
  • в C ++ 17, if constexpr (ваш пример работает с обычными if)

    template <E e> class X
    { 
    public:
        void f_common() const { std::cout << "common" << std::endl; }
        void f() const
        {
            if constexpr (e == E::E1) {
                std::cout << "E1" << std::endl;
            } else {
                std::cout << "E2" << std::endl;
            }
        }
    };
    
  • requires в C ++ 20:

    template <E e> class X
    { 
    public:
        void f_common() const { std::cout << "common" << std::endl; }
        void f() const requires(e == E::E1) { std::cout << "E1" << std::endl;}
        void f() const requires(e == E::E2) { std::cout << "E2" << std::endl;}
    };
    
2 голосов
/ 26 марта 2020

Короче говоря : специализация шаблона не будет "наследовать" ничего от шаблона, потому что вы полностью "перезапишите" реализацию шаблона, специализируя его.

Длинный ответ : похоже, вы перепутали специализацию шаблонов с наследованием. Если вы действительно хотите использовать шаблон класса, вам нужно создать его экземпляр, тем самым (неявно или явно) вы создадите группу совершенно новых классов. В отличие от наследования классов, между этими классами нет никакой связи, в результате, например, если вы написали функцию, которая принимает X<E::E1> в качестве параметра, то компилятор отклонит вызов его с объектом X<E::E2>.

Специализация шаблона используется для предоставления специальных реализаций некоторым указанным c параметрам шаблона. Задавая специализацию шаблона, вы попросили компилятор использовать специальную реализацию вместо создания нового класса из реализации generi c. Поэтому и X<E::E1>, и X<E::E2> не содержат метод f_common(), потому что объявление f_common не появляется в специализированных реализациях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...