c++ - C++模板类:运行时给出的模板参数,如何避免重复的大开关情况?
问题描述
我目前正在开发一个图像处理应用程序,主要基于 C++ 和 ITK。
一、情况
我有FlipFilter
从同一个基类派生的节点类(例如)。一个节点获得一个结构,其中包含一个image_ptr
和所有元信息(的维度Image
,PixelType
(例如RGB,RGBA,标量)和ComponentType
(例如浮点数,整数)。节点必须实例化一个ITK-Filter
,基于这些Meta-Informations
,它可以改变每个输入图像。
2.问题
这些ITK-Filters
需要ImageType
(例如 RGB 和ComponentType UCHAR
)作为模板参数。模板类必须在编译时实例化。我的节点在运行时获取具有其类型的图像。所以我必须以某种方式为每个节点创建过滤器的所有排列,然后使用适当的实例化。
3.我目前的解决方案
该结构包含所有元信息+指向实际图像的智能指针。我正在使用图像的基本指针,因为图像本身也是一个模板(稍后我正在向下转换)。
struct ImageData
{
short NumberOfDimensions;
itk::ImageIOBase::IOComponentType ComponentType;
itk::ImageIOBase::IOPixelType PixelType;
itk::DataObject::Pointer Image;
ImageData() {}
~ImageData() {}
};
这是我节点的更新功能。它应该创建过滤器并在图像上执行它。
void LitkFlipImageFilter::update()
{
if (Input1 == nullptr)
throw(std::runtime_error("Input1 not set"));
Input1->update();
ImageData Input1Data = Input1->getOutput();
switch (Input1Data.PixelType)
{
default:
{
throw std::runtime_error("Type not Supported");
break;
}
case itk::ImageIOBase::RGB:
{
switch (Input1Data.ComponentType)
{
default:
{
throw std::runtime_error("Type not Supported");
break;
}
case itk::ImageIOBase::IOComponentType::UCHAR:
{
using PixelType = itk::RGBPixel< unsigned char >;
using ImageType = itk::Image < PixelType, 2 >;
itk::FlipImageFilter<ImageType>::Pointer filter = itk::FlipImageFilter<ImageType>::New();
//do stuff
break;
}
break;
}
}
}
}
4. 我的解决方案的问题
它可以工作,但会创建大量重复代码和大型嵌套开关案例。你知道解决这个问题的更优雅的方法吗?
谢谢!
解决方案
您想要的高级处理是:
template <typename PixelType>
void do_stuff()
{
using ImageType = Image < PixelType, 2 >;
...do stuff...
}
您可以创建一个冗长但可重用的(通过改变“Fn”代码来调度)版本的切换代码:
template <typename Fn>
void dispatch(PixelType pt, ComponentTypeId ct, Fn fn) {
switch (pt)
{
case RGB:
switch (ct) {
case Uint8_t: fn(RGBPixel<uint8_t>{}); return;
case Float: fn(RGBPixel<float>{}); return;
};
case RGBA:
switch (ct) {
case Uint8_t: fn(RGBAPixel<uint8_t>{}); return;
case Float: fn(RGBAPixel<float>{}); return;
};
case Scalar:
switch (ct) {
case Uint8_t: fn(ScalarPixel<uint8_t>{}); return;
case Float: fn(ScalarPixel<float>{}); return;
};
}
}
然后,这样称呼它:
dispatch(runtime_pixel_type, runtime_component_type,
[](auto pt) { do_stuff<decltype(pt)>(); });
笔记:
对 lambda 使用默认构造的“XXXPixel”参数是丑陋的——C++2a 应该引入适当的模板化 lambda,可能(?!)清理它。
您可以链接多个“调度”函数,每个调度基于一个运行时变量,以避免开关情况的乘法爆炸;这可以更好地扩展,但在这里有点过分了,你必须努力
PixelType
成为一个模板。您可以
default: throw
重新添加您的 s - 不需要break
(或return
)在它们之后,因为它们永远不会返回到以下代码行
推荐阅读
- python-3.x - Vpython访问从pdb蛋白质文件加载的对象
- c# - 如何根据c#中方法的参数设置数组的大小?
- proxy - 我无法通过代理访问我的 apollo 服务器
- java - 带有 Redis Sentinel 的 Spring Boot 缓存始终连接到主节点
- javascript - 使上传的图像文件可以通过 URL 访问的正确方法是什么 - google drive api v3
- python - 在 Python 中创建一个 json 对象
- javascript - 绕过浏览器音频处理
- python - 如何使用列表值创建颜色渐变 1D 热图(带状图)?
- c++ - 为多态类实现复制构造函数
- r - 如何使用闪亮的输入来过滤已编辑的数据表?