Контейнер указателей на производный класс из класса шаблона с общим предком в качестве аргумента шаблона - PullRequest
0 голосов
/ 06 мая 2020

У меня есть суперкласс, который моделирует Measurement и два производных класса: PointCloudMeasurement и ImageMeasurement.

Другой шаблонный суперкласс, Handler<MeasT>, определяет интерфейс для обработки измерения.

Два класса обработчиков, PointCloudHandler и ImageHandler, специализируются на классе Handler с соответствующими типами измерений как аргументы шаблона.

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

Вот code ( link ):

// Example program
#include <iostream>
#include <string>
#include <vector>
#include <memory>

class Measurement {
public:
  uint64_t time;
  virtual ~Measurement() {}
};

class PointCloudMeasurement : public Measurement {
public:
  uint64_t n_points = 64*1024;

};

class ImageMeasurement : public Measurement {
public:
  uint64_t n_pixels = 640*480;

};

template<class MeasT = Measurement>
class Handler {
public:
  virtual void addMeasurement(MeasT& m) = 0;
};

class PointCloudHandler : public Handler<PointCloudMeasurement> {
public:
  void addMeasurement(PointCloudMeasurement& m) override {
    std::cout << m.n_points << std::endl;
  }
};

class ImageHandler : public Handler<ImageMeasurement> {
  void addMeasurement(ImageMeasurement& m) override {
    std::cout << m.n_pixels << std::endl;

  }

};


int main(void){
  std::vector<std::unique_ptr<Handler<Measurement>>> handlers;

  handlers.push_back(std::make_unique<PointCloudHandler>());
  handlers.push_back(std::make_unique<ImageHandler>());

  PointCloudMeasurement pcm;
  ImageMeasurement im;

  handlers[0]->addMeasurement(pcm);
  handlers[1]->addMeasurement(im);
}

что дает мне:

In function 'int main()':
50:59: error: no matching function for call to 'std::vector<std::unique_ptr<Handler<Measurement> > >::push_back(std::_MakeUniq<PointCloudHandler>::__single_object)'
50:59: note: candidates are:
In file included from /usr/include/c++/4.9/vector:64:0,
                 from 4:
/usr/include/c++/4.9/bits/stl_vector.h:913:7: note: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::unique_ptr<Handler<Measurement> >; _Alloc = std::allocator<std::unique_ptr<Handler<Measurement> > >; std::vector<_Tp, _Alloc>::value_type = std::unique_ptr<Handler<Measurement> >]
       push_back(const value_type& __x)
       ^
/usr/include/c++/4.9/bits/stl_vector.h:913:7: note:   no known conversion for argument 1 from 'std::_MakeUniq<PointCloudHandler>::__single_object {aka std::unique_ptr<PointCloudHandler, std::default_delete<PointCloudHandler> >}' to 'const value_type& {aka const std::unique_ptr<Handler<Measurement> >&}'
/usr/include/c++/4.9/bits/stl_vector.h:931:7: note: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = std::unique_ptr<Handler<Measurement> >; _Alloc = std::allocator<std::unique_ptr<Handler<Measurement> > >; std::vector<_Tp, _Alloc>::value_type = std::unique_ptr<Handler<Measurement> >]
       push_back(value_type&& __x)
       ^
/usr/include/c++/4.9/bits/stl_vector.h:931:7: note:   no known conversion for argument 1 from 'std::_MakeUniq<PointCloudHandler>::__single_object {aka std::unique_ptr<PointCloudHandler, std::default_delete<PointCloudHandler> >}' to 'std::vector<std::unique_ptr<Handler<Measurement> > >::value_type&& {aka std::unique_ptr<Handler<Measurement> >&&}'
51:54: error: no matching function for call to 'std::vector<std::unique_ptr<Handler<Measurement> > >::push_back(std::_MakeUniq<ImageHandler>::__single_object)'
51:54: note: candidates are:
In file included from /usr/include/c++/4.9/vector:64:0,
                 from 4:
/usr/include/c++/4.9/bits/stl_vector.h:913:7: note: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::unique_ptr<Handler<Measurement> >; _Alloc = std::allocator<std::unique_ptr<Handler<Measurement> > >; std::vector<_Tp, _Alloc>::value_type = std::unique_ptr<Handler<Measurement> >]
       push_back(const value_type& __x)
       ^
/usr/include/c++/4.9/bits/stl_vector.h:913:7: note:   no known conversion for argument 1 from 'std::_MakeUniq<ImageHandler>::__single_object {aka std::unique_ptr<ImageHandler, std::default_delete<ImageHandler> >}' to 'const value_type& {aka const std::unique_ptr<Handler<Measurement> >&}'
/usr/include/c++/4.9/bits/stl_vector.h:931:7: note: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = std::unique_ptr<Handler<Measurement> >; _Alloc = std::allocator<std::unique_ptr<Handler<Measurement> > >; std::vector<_Tp, _Alloc>::value_type = std::unique_ptr<Handler<Measurement> >]
       push_back(value_type&& __x)
       ^
/usr/include/c++/4.9/bits/stl_vector.h:931:7: note:   no known conversion for argument 1 from 'std::_MakeUniq<ImageHandler>::__single_object {aka std::unique_ptr<ImageHandler, std::default_delete<ImageHandler> >}' to 'std::vector<std::unique_ptr<Handler<Measurement> > >::value_type&& {aka std::unique_ptr<Handler<Measurement> >&&}'

Я не понимаю, почему преобразование указателя не работает, поскольку все производные классы наследуются от Handler<MeasT>, где MeasT является производным от Measurement.

Я встречал похожие вопросы, но большинство из них сохраняют шаблон даже в производном классе (чего у меня нет) или обратитесь к CRTP. Однако CRTP напрямую использует производный класс в качестве аргумента шаблона, а здесь я использую другой производный класс.

1 Ответ

0 голосов
/ 06 мая 2020

Подумайте только, что компилятор C ++ заменит имя класса при создании шаблона. Итак, ваше объявление ha sh map переведено таким образом std :: vector >> handlers; -> std :: vector> обработчики; означает, что компилятор автоматически создаст «шаблонный класс» из обработчика шаблона класса, как показано ниже

class Handler_Measurement {
  public:
   virtual void addMeasurement(Measurement& m) = 0;
 };

, но когда компилятор видит handlers.push_back (std :: make_unique ()); он создает следующие шаблонные классы:

  class Handler_PointCloudMeasurement {
  public:
   virtual void addMeasurement(PointCloudMeasurement& m) = 0;
 };

  class PointCloudHandler : public Handler_PointCloudMeasurement {
    public:
      void addMeasurement(PointCloudMeasurement& m) override {
         std::cout << m.n_points << std::endl;
      }
    };

и для handlers.push_back (std :: make_unique ()); компилятор создает класс Handler_ImageMeasurement {publi c: virtual void addMeasurement (ImageMeasurement & m) = 0; };

     class ImageHandler : public Handler_ImageMeasurement{
       void addMeasurement(ImageMeasurement& m) override {
         std::cout << m.n_pixels << std::endl;
       }
      };

Из образца кода, созданного вручную, вы можете видеть, что базовые классы отличаются. Таким образом, решение, подобное приведенному ниже, может вам помочь.

#include <iostream>
#include <string>
#include <vector>
#include <memory>

class Measurement {
 public:
uint64_t time;
virtual ~Measurement() {}
virtual void display() = 0;
 };

 class PointCloudMeasurement : public Measurement {
  public:
uint64_t n_points = 64 * 1024;

void display()
{
    std::cout << n_points << std::endl;
}

  };

  class ImageMeasurement : public Measurement {
   public:
uint64_t n_pixels = 640 * 480;

void display()
{
    std::cout << n_pixels << std::endl;
}
  };

  class Handler {
  public:
virtual void addMeasurement(Measurement& m) = 0;
  };

  class PointCloudHandler : public Handler {
  public:
void  addMeasurement(Measurement& m) override {
    m.display();
}
  };

  class ImageHandler : public Handler {
void  addMeasurement(Measurement& m) override {
    m.display();
}
  };


  int main(void) {
std::vector<std::unique_ptr<Handler>> handlers;

handlers.push_back(std::make_unique<PointCloudHandler>());
handlers.push_back(std::make_unique<ImageHandler>());

PointCloudMeasurement pcm;
ImageMeasurement im;

handlers[0]->addMeasurement(pcm);
handlers[1]->addMeasurement(im);
 }

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

Надеюсь, это поможет.

...