gpt4 book ai didi

c++ - 将基于模板的私有(private)实现桥接到非模板化公共(public) API

转载 作者:太空宇宙 更新时间:2023-11-04 13:52:40 25 4
gpt4 key购买 nike

我想利用 C++ 模板实现代码重用和类型安全,但我一直发现自己在 API 边缘做一些相当笨重的事情来在基于模板的实现和外部接口(interface)(运行时数据)之间转换基于。我想知道是否有某种方法可以让编译器帮助完成一些转换(即为我做一些这样的工作。)

让我们考虑一个人为的情况,我们想对图像进行一些操作,比如将其转换为另一个颜色空间。假设我们有一些任意的图像类:

struct Image { /* Whatever */ };

然后我们有一个我们支持的转换类型的枚举:

enum class ImageType : uint8_t {
RGB,
CMYK,
Grayscale
};

然后我们得到了一些私有(private)实现,这些实现被模板化以重用代码等:

// Internal implementation
template <ImageType T>
struct ImageConverter {
public:
Image ConvertImage(const Image& img);
private:
void some_shared_code(Image& img) {
// do stuff...
};
};

然后我们得到了每种类型的一些方法实例。 (请注意,对于调用者而言,这些都共享相同的返回类型和参数列表)。

template <> Image ImageConverter<ImageType::RGB>::ConvertImage(const Image& img)
{
Image foo = img;
some_shared_code(foo);
// do other stuff specific to this color space...
return foo;
};

template <> Image ImageConverter<ImageType::CMYK>::ConvertImage(const Image& img)
{
Image foo = img;
some_shared_code(foo);
// do other stuff specific to this color space...
return foo;
};

template <> Image ImageConverter<ImageType::Grayscale>::ConvertImage(const Image& img)
{
Image foo = img;
some_shared_code(foo);
// do other stuff specific to this color space...
return foo;
};

最后,我们想将其作为非模板化 API 向外界公开,如下所示:

Image ConvertImage(const Image& inImage, ImageType toType) {
switch (toType) {
case ImageType::RGB: {
ImageConverter<ImageType::RGB> ic;
return ic.ConvertImage(inImage);
}
case ImageType::CMYK: {
ImageConverter<ImageType::CMYK> ic;
return ic.ConvertImage(inImage);
}
case ImageType::Grayscale: {
ImageConverter<ImageType::Grayscale> ic;
return ic.ConvertImage(inImage);
}
}
};

让我困扰的是最后一部分——它既丑陋又笨拙。就其值(value)而言,这显然是一个为简洁起见而使用非类型模板参数的人为示例,但问题存在于抽象中(即当模板参数是类型时。)

我知道声明一个纯虚拟“接口(interface)”类的模式,然后您的所有模板实例化都从该类继承,但这需要模板实例化从接口(interface)类继承。使用第三方类时,有时这并不是一个真正的选择。 (它还有其他缺点,比如改变内存中的布局等)

是否有一些习惯用法,在那个抽象空间中工作,可以更优雅地填补这个 switch 语句的角色,而不需要对实现进行繁重的更改(例如从非模板化接口(interface)类继承) )?我觉得这一定是一个常见问题,并且可能有一些聪明的解决方案超出了我当前的模板功能的范围。

编辑:我对此思考得越多,我就越开始认为答案可能是基于模板元编程的(因为模板元编程是任何问题的答案。)

最佳答案

我想到的一个可能的解决方案是使用类型标签而不是枚举:

struct RGBConv{};
struct CMYKConv{};
struct GrayscaleConv{};

然后你可以像这样声明ImageConverter:

struct ImageConverter {
public:
template <typename ConvT>
Image ConvertImage(const Image& img, ConvT conv);
private:
void some_shared_code(Image& img) {
// do stuff...
};
};

然后在每个图像转换器类型上专门化 ConvertImage:

template <> Image ImageConverter::ConvertImage<RGBConv>(const Image& img, RGBConv conv){/*...*/}
template <> Image ImageConverter::ConvertImage<CMYKConv>(const Image& img, CMYKConv conv){/*...*/}
template <> Image ImageConverter::ConvertImage<GrayscaleConv>(const Image& img, GrayscaleConv conv){/*...*/}

现在我们可以去掉 switch 语句了:

template <typename T>
Image ConvertImage(const Image& inImage, T conv) {
return ImageConverter().ConvertImage(inImage, conv);
};

是的,ConvertImage 仍然是模板函数,但多亏了 ADL,我们可以像这样调用它:

ConvertImage(Image(), RGBConv());
ConvertImage(Image(), GrayscaleConv());

关于c++ - 将基于模板的私有(private)实现桥接到非模板化公共(public) API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22863460/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com