C ++模板类:运行时给定的模板参数,如何避免重复出现大开关情况?

时间:2018-08-12 13:22:57

标签: c++ image-processing generic-programming itk

我目前正在研究主要基于C ++和ITK的图像处理应用程序。

1。情况

我有从同一基本类派生的节点类(例如FlipFilter)。节点使用image_ptr和所有元信息(ImagePixelType(例如RGB,RGBA,标量)和ComponentType(例如浮点数(int)。节点必须基于这些ITK-Filter实例化一个Meta-Informations,该ITK-Filters可以在每个输入图像上更改。

2。问题

这些ImageType需要使用ComponentType UCHAR(例如,带有struct ImageData { short NumberOfDimensions; itk::ImageIOBase::IOComponentType ComponentType; itk::ImageIOBase::IOPixelType PixelType; itk::DataObject::Pointer Image; ImageData() {} ~ImageData() {} }; 的RGB)作为模板参数。模板类必须在编译时实例化。我的节点正在运行时获取其类型的图像。因此,我必须以某种方式为每个节点创建过滤器的所有置换,然后使用适当的实例化。

3。我当前的解决方案

此结构包含指向实际图像的所有元信息 + 智能指针。 我使用图像的基本指针,因为图像本身也是模板(后来我向下转换)。

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;
            }
        }
    }
}

这是我节点的更新功能。应该创建过滤器并在图像上执行它。

error

4。我的解决方案有问题

它可以正常工作,但是会创建许多重复的代码和大型的嵌套开关盒。您知道解决此问题的更优雅的方式吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

您想要的高级处理是:

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添加回去-无需再添加break(或return),因为它们永远不会返回到以下代码行