我的问题涉及创建C ++函数或类似构造以返回typename的可能性(与典型的某种类型的对象/引用/指针相反)。
如下面的代码所示,我有一个通用的“ Image”类,它仅包含一个指向数据的指针(void *),数据的大小以及一个定义数据表示方式的成员变量。我需要灵活地用同一类来表示8位,16位,...图像类型。
[当我要处理图像数据时,当前必须使用switch / case构造(如示例CopyImage()
中所示))在复制之前将void *数据指针重新解释_cast为适当的类型。不幸的是,当我使用执行除CopyImage()以外的功能的函数进行扩展时,相同的切换/案例范例一直在各地重复出现。似乎是混乱且重复的,并且限制了我增加对更多类型的支持的能力,而又无法将大量其他函数复制到其他情况下。
enum class datatype_t {
u8,
u16
};
class Image { // can be an image with 8 or 16-bit pixel representation
public:
void * dataPtr_;
datatype_t dataType_;
size_t pixels_;
};
void CopyImage(Image& source, uint16_t * dst_ptr) { // function to copy image agnostic to data represenation
switch (source.dataType_) {
case datatype_t::u8:
std::copy_n(reinterpret_cast<uint8_t*>(source.dataPtr_), source.pixels_, dst_ptr);
break;
case datatype_t::u16:
std::copy_n(reinterpret_cast<uint16_t*>(source.dataPtr_), source.pixels_, dst_ptr);
break;
}
}
int main()
{
const size_t image_size = 100;
std::vector<Image> image_library;
// create Image objects, populate details, push to image library
Image source_image8;
source_image8.dataType_ = datatype_t::u8;
source_image8.pixels_ = image_size;
source_image8.dataPtr_ = new uint8_t[image_size];
image_library.push_back(std::move(source_image8));
Image source_image16;
source_image16.dataType_ = datatype_t::u16;
source_image16.pixels_ = image_size;
source_image16.dataPtr_ = new uint16_t[image_size];
image_library.push_back(std::move(source_image16));
auto destination = new uint16_t[image_size];
CopyImage(image_library[0], destination); // copy a 8-bit image into 16-bit destination
CopyImage(image_library[1], destination); // copy a 16-bit image into 16-bit destination
// deletes, etc to follow (not shown for conciseness)
}
我想要是我可以包含在reinterpret_cast
的<...>中的函数,调用该函数时,它返回类型名(即uint8_t,uint16_t等)。该函数将是Image类的成员函数,引用dataType_变量,并提供一个类型名-类似于switch / case语句为每种可能的类型显式执行的操作-但仅需将其维护一次。一个可以在我尝试执行reinterpret_cast <>操作的任何地方调用的函数。
例如,一个名为Image::ReturnType()
的函数,可以像这样使用:
std::copy_n(reinterpret_cast<source.ReturnType()>(source.dataPtr_), source.pixels_, dst_ptr);
并定义如下:
typename Image::ReturnType() {
switch (dataType_) {
case u8:
return uint8_t;
case u16:
return uint16_t;
}
}
我意识到这个问题是在寻求一种利用多态性或与模板化Image类相关的解决方案,以便我具有单独的Image<uint8_t>
和Image<uint16_t>
类型,但是这使我无法存储一堆Image对象(具有不同的像素表示形式)在单个std::vector<Image>
中。
注意:如果有一种方法可以在一个std::vector
中存储具有不同模板类型专门化的对象,那么我也愿意采用该解决方案,但恐怕这种方法不存在。
非常感谢!
在编译时必须知道所有类型。类型是编译时抽象。在运行时,类型或多或少地存在。
您的dataType_
变量在编译时是否已知?如果是,那么当然可以有一个返回类型的元函数:
using TypeMap = std::tuple<uint8_t, uint16_t>;
struct Image {
// ...
template<datatype_t datatype_id>
using ReturnType = std::tuple_element_t<static_cast<std::size_t>(datatype_id), TypeMap>;
};
然后您可以使用元功能:
// the_type_to_use is uint8_t
using the_type_to_use = Image::ReturnType<datatype_t::u8>;
另一方面,如果仅在运行时知道该值,则必须使用运行时distpatch。无论是通过变量表还是通过虚拟表。
编号
一个函数只能返回对象或引用(或无效)。
您可以使用模板化类型别名或类模板的成员类型别名将值映射到类型。示例:
template<datatype_t>
struct image_return_type {};
template<>
image_return_type<u8> {
using type = std::uint8_t;
};
template<>
image_return_type<u16> {
using type = std::uint16_t;
};