c++ - 从具有共同祖先的模板类指向派生类的指针容器作为模板参数
问题描述
我有一个超类,它模拟一个Measurement
和两个派生类:PointCloudMeasurement
和ImageMeasurement
.
另一个模板化的超类,Handler<MeasT>
定义了处理测量的接口。
两个处理程序类,PointCloudHandler
并使用相应的测量类型作为模板参数ImageHandler
专门化该类。Handler
我想使用指向超类的指针容器来跟踪所有处理程序,并根据手头处理程序的派生类型调用适当的方法。
这是代码(链接):
// 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>
whereMeasT
是Measurement
.
我见过类似的问题,但他们中的大多数甚至将模板保留在派生类中(我没有)或参考 CRTP。但是,CRTP 直接使用派生类作为模板参数,而这里我使用的是不同的派生类。
解决方案
试想一下,当我们模板化时,C++ 编译器会替换类名。因此,您的哈希映射声明以这种方式翻译 std::vector>> 处理程序;--> 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 { public: 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);
}
此外,您的派生类在数据成员方面也有所不同。它们唯一的共同点是“它们是一种测量类型”,但它们没有任何共同点。
我希望它有所帮助。
推荐阅读
- java - 如何使用 Hibernate 在单个实体中访问来自两个数据库的数据?
- php - 为什么 array_search 函数在被要求搜索未包含的值时返回 0 元素的键?
- html - 如何修复导航对齐并将图标添加到导航栏?
- string - Generate random string WITHOUT time?
- php - 将复杂查询从 Laravel 转换为 SQL
- java - 我可以将我在代码中编写的字符串中的数据存储在 SQlite 数据库中吗?
- python - Python 错误:行继续字符后出现意外字符。我该怎么办?
- azure-devops - 尝试将 webjob 添加到 Azure DevOps 发布管道
- google-apps-script - 使用 Google Apps 脚本修改 BigQuery 数据
- pentaho - Petaho 报表设计器内容字段中的动态 URL