我希望有可能编写一个模板类,该类将为多个特定于类型的子类继承。我希望继承的方法和运算符返回子类的类型,而不是父模板的类型。如果我只需要修改一个基类,这是希望节省很多开发和维护工作。
这是我已经拥有的示例:
template<typename T> struct TMonoPixel
{
T value;
TMonoPixel(T v) { value = v; }
// the template has some pure virtual functions here...
TMonoPixel operator+ (const TMonoPixel& other)
{ return TMonoPixel(value + other.value); }
}
struct Mono8Pixel : TMonoPixel<uint8_t>
{
using TMonoPixel::TMonoPixel; // I want to inherit the constructor
// each pixel type implements the virtual functions in the template
}
如您所见,Mono8Pixel结构继承了
+
运算符,该运算符接受TMonoPixel
,但是使用此运算符将返回TMonoPixel<uint8_t>
而不是Mono8Pixel
,因为它是在基类中定义的。我打算使用这些结构遍历图像中的像素:
Image* img; // img has an unsigned char* pointer to its pixel data
for (int row=0; row<img->height; row++) {
for (int col=0; col<img->width; col++) {
int i = (row*img->width + col);
Mono8Pixel* pixel = reinterpret_cast<Mono8Pixel*>(img->dataPtr + sizeof(unsigned char)*i);
// modify the pixel ...
}
}
有什么方法可以只更改模板类以确保
Mono8Pixel(2) + Mono8Pixel(2)
返回Mono8Pixel
吗?请注意,无论解决方案是什么,由于我希望如何使用它们,这些结构都必须保持标准布局。
最佳答案
您可以使用奇怪的重复模板模式(CRTP)来完成所需的操作。基本思想是这样的:
template<class Pixel> struct TMonoPixel {
...
// not virtual
std::string GetSomeProperty() const {
return static_cast<const Pixel&>(*this).GetSomeProperty();
}
Pixel operator+(const TMonoPixel& other) const {
return Pixel(value + other.value);
}
};
struct Mono8Pixel : TMonoPixel<Mono8Pixel> {
using TMonoPixel::TMonoPixel;
std::string GetSomeProperty() const {
return "My name is Mono8Pixel";
}
};
由于隐式派生到基本转换,现在您可以像这样使用它:
template<class T>
void foo(const TMonoPixel<T>& number) {
std::cout << number.GetSomeProperty();
}
Mono8Pixel i;
foo(i);
请注意,在
TMonoPixel
内部,Pixel
是不完整的类型,因此在使用方式上有一些限制。例如,您不能执行以下操作:template<class Pixel> struct TMonoPixel {
Pixel::Type operator+(const TMonoPixel& other);
};
struct Mono8Pixel : TMonoPixel<Mono8Pixel> {
using Type = std::uint8_t;
};
类型特征是克服此类限制的有用技术:
struct Mono8Pixel;
template<class Pixel> struct ValueType;
template<> struct ValueType<Mono8Pixel> {
using Type = std::uint8_t;
};
template<class Pixel> struct TMonoPixel {
using Type = typename ValueType<Pixel>::Type;
Type value;
TMonoPixel(Type value) : value(value)
{}
Pixel operator+(const TMonoPixel& other) const {
return Pixel(value + other.value);
}
};
struct Mono8Pixel : TMonoPixel<Mono8Pixel> {
using TMonoPixel::TMonoPixel;
};
Mono8Pixel(2) + Mono8Pixel(2)
的类型是Mono8Pixel
。他们是这样:
static_assert(std::is_standard_layout_v<Mono8Pixel>);
完整的示例:https://godbolt.org/z/8z0CKX
关于c++ - 如何用运算符编写可继承的模板类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56482314/