Указатели на шаблонный класс

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

template<class T1, class T2>
class Vertex {
public:
  virtual T1 run(T2) = 0;
};


class Graph {
  std::map<std::string, Vertex*> vertices; // <--- How do I do something like this
  int** adjacency_matrix;
public:
  void run() {
     ...
  }
};

Я рассматривал некоторые другие вопросы по Stack-Overflow, общее предложение, похоже, состоит в том, чтобы использовать базовый класс, который не является шаблоном, и использовать для этого указатели и помещать общие функции в этот класс. Однако в моем коде функция run(), которая является общей и использует шаблон для типа возвращаемого значения. Поэтому я не понимаю, как использовать базовый класс.

Любые идеи?

Если функция Vertex::run использует аргументы шаблона и вы хотите сохранить указатели на Vertex без аргументов шаблона, как вы собираетесь вызывать Vertex::run? Что вы собираетесь на это переходить?   —  person ssb    schedule 24.06.2014

Вот такая у меня проблема. Есть ли у вас какие-либо предложения, чтобы обойти это?   —  person ssb    schedule 24.06.2014

C ++ имеет статическую типизацию, поэтому ему необходимо знать тип во время компиляции. Это означает, что ему нужно знать, что такое T2, если вы собираетесь позвонить run(T2). Вы можете объявить несколько карт в Graph, по одной для каждой комбинации аргументов шаблона Vertex, которые вы используете, но это звучит не очень хорошо. Возможно, вам придется пересмотреть свой дизайн и посмотреть, есть ли другой способ решения вашей проблемы. Чего вы пытаетесь достичь? Вы можете задать другой вопрос, более направленный на это.   —  person ssb    schedule 24.06.2014

Как вы собираетесь взаимодействовать с Vertexs, когда они окажутся в Graph, не зная их типа?   —  person ssb    schedule 24.06.2014

См. также:  Почему допустимо переплетать операторы switch / for / if в C / C ++?
Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 3
  1. ssb

    Класса с именем Vertex не существует, только шаблон для классов.

    Простой выход — использовать полиморфизм, так как вы все равно храните только указатели:

    Определите базовый класс, от которого наследуются все Vertex экземпляры (специализированные или нет).

    template<class T1, class T2>
    class Vertex : VertexBase {
    public:
      virtual T1 run(T2) = 0;
    };
    
    struct VertexBase {
      ~VertexBase() = default;
      template<class T1, class T2> T1 run(T2 x) {
        return dynamic_cast<Vertex<T1,T2>&>(*this).run(x);
      }
    };
    

    В любом случае, также взгляните на std::function и посмотрите, достаточно ли это решает вашу проблему.

    Проблема с базовым классом заключается в том, что мне нужно использовать функцию run(), которая использует шаблон. Как определить это в базовом классе? person ssb; 24.06.2014

    Добавлен пример использования шаблона в базовом классе для вызова run. person ssb; 24.06.2014

  2. ssb

    Вы можете указать такой тип:

    std::map<std::string, Vertex<int, int>*> vertices;
    

    Или сделайте Graph шаблонным:

    template<class T1, class T2>
    class Graph {
        std::map<std::string, Vertex<T1, T2>*> vertices;
    

    Дело в том, что карта может иметь разные реализации шаблона класса Vertex. Например, одна запись может быть Vertex<int, int>, другая может быть Vertex<double, long> и т. Д. person ssb; 24.06.2014

    @subzero Можете воспользоваться моим вторым предложением. person ssb; 24.06.2014

    Но когда я создаю экземпляр объекта Graph в этом случае, я бы застрял только с одним типом объектов Vertex. person ssb; 24.06.2014

    Нет, вы можете сделать Graph<double, long>. person ssb; 24.06.2014

    Я имею в виду, что если я создам экземпляр, скажите Graph<int, int> x. Тогда я не могу x.vertices['xyz'] = 1.12121. person ssb; 24.06.2014

    @subzero Создайте базовый класс, от которого наследуется Vertices. Теперь замените Vertices* на карте на Base* (или любое другое имя по вашему выбору). Затем вы можете динамически выделить класс шаблона с нужными параметрами. Но также рекомендуется использовать интеллектуальные указатели, такие как std::shared_ptr, чтобы управлять памятью за вас. :) person ssb; 24.06.2014

    @ 0x499602D2 Но как мне определить функцию run() в Base (которая использует шаблон)? Я не могу получить доступ к функции run() из Base*. person ssb; 24.06.2014

    @CoffeeandCode. Когда вы запускаете код из этого ответа и вызываете run(), вы получаете эту ошибку. person ssb; 24.06.2014

  3. ssb

    Во-первых, как я уже сказал, вам нужен не шаблонный базовый класс, от которого Vertex наследуется:

    struct Base
    {
        virtual ~Base() = default;
    };
    
    template<class T1, class T2>
    class Vertex : public Base
    {
    public:
        virtual T1 run(T2) = 0;
    };
    

    Затем внутри вашей Graph функции вы используете std::shared_ptr<Base> вместо Vertex*:

    class Graph {
        std::map<std::string, std::shared_ptr<Base>> vertices;
    public:
        void run();
    };
    

    Теперь при вызове run() указателя Vertex вам нужно dynamic_cast вернуть указатель обратно на соответствующий производный класс. В вашем случае вы не можете вызвать run() на Vertex*, поскольку Vertex::run() — это чистая виртуальная функция.

    int main()
    {
        Graph g;
        g.vertices["xyz"] = std::make_shared<Vertex<int, int>>();
        // error: field type 'Vertex<int, int>' is an abstract class
    }
    

    Если вы хотите вызвать Vertex, либо сделайте run() не чистой виртуальной функцией и дайте ей реализацию, либо используйте производный класс для реализации:

    class Derived : public Vertex<int, int>
    {
    public:
        int run(int n) { std::cout << n << '\n'; return 0; }
    };
    
    class Graph {
        std::map<std::string, std::shared_ptr<Base>> vertices;
    public:
        template<class T2>
        void call_run(std::shared_ptr<Base> p, T2 value)
        {
            if (auto derived = std::dynamic_pointer_cast<Derived>(p))
                derived->run(value);
    
            if (/* other derived classes... */);
        }
    
        void run();
    };
    
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: