gpt4 book ai didi

c++ - 以在编译时和运行时都可用的方式在 C++ 中描述像素格式信息

转载 作者:IT老高 更新时间:2023-10-28 22:15:09 24 4
gpt4 key购买 nike

我有一个对像素进行操作的库。像素可以有许多不同的格式。我正在寻找一种有效的方式来描述库 API 中的格式(内部和外部)。

对于某些类,像素格式是模板参数,对于其他类,它是运行时参数。因此像素格式需要在运行时(作为构造函数或函数参数)和编译时(作为模板参数)都可用。我只想描述一次像素格式

我现在是这样的:

enum class color_space : uint8_t { rgb, cmyk /* , etc... */ };

struct pixel_layout {
color_space space;
uint8_t channels;
/* etc... */
};

template <color_space ColorSpace, uint8_t Channels /* etc.. */>
struct pixel_type {
static constexpr color_space space = ColorSpace;
static constexpr uint8_t channels = Channels;
/* etc... */

static constexpr pixel_layout layout() {
return {space, channels /* , etc... */ };
}
};

struct rgb : public pixel_type<color_space::rgb, 3 /* , etc... */ > {};
struct rgba : public pixel_type<color_space::rgb, 4 /* , etc... */ > {};

这很好用。我可以将它们用作运行时和编译时参数:

template <class PixelType>
class image { };

struct transform {
transform(const pixel_layout from, const pixel_layout to)
: from(from), to(to) { /* ... */ }

pixel_layout from;
pixel_layout to;
};

同时从编译时类型转换为运行时类型:

transform(rgb::layout(), rgba::layout());

但是,复制和存储 pixel_layout在运行时使用像素类型的细节对我来说似乎很愚蠢。从概念上讲,程序只需要一个 ID/地址/对特定 pixel_type 的引用。以及在编译时和运行时检索相关属性(颜色空间、 channel 等)的方法。

另外,如果我想从像素类型中获取派生属性,我需要在 pixel_layout 上实现它。如果我想避免重复逻辑。然后要在编译时使用它,我需要从 pixel_type<...>上课至pixel_layout派生属性的实例。这也有点傻。

我可以避免绕过pixel_layout吗?详细信息,而是使用某种对 pixel_type<...> 的引用(子)类?

我尝试使用 enum s,因为枚举用作模板参数和函数参数。但是我很难在运行时从枚举值(例如 rgba )获取像素类型属性(例如 4 个 channel )并以惯用的 C++ 方式进行编译。

此外,枚举作为模板参数在编译错误期间提供的诊断功能要少得多。例如,我得到 image<(pixel_type)2>而不是 image<rgba>在用 clang 编译错误消息。所以这似乎不是一个有用的方法。

最佳答案

使用非类型引用模板参数可能是一种解决方案。见 http://en.cppreference.com/w/cpp/language/template_parameters .比如这样:

#include <iostream>
#include <cstdint>
#include <array>

enum class color_space : std::uint8_t { rgb, cymk, other };

// PIXEL LAYOUT
// Can be created/modified at runtime, but a predefined set of pixel_layouts
// exists for compile-time use.
struct pixel_layout {
color_space space;
std::uint8_t channels;
};

constexpr bool operator==(const pixel_layout& a, const pixel_layout& b) {
return (a.space == b.space) && (a.channels == b.channels);
}
constexpr bool operator!=(const pixel_layout& a, const pixel_layout& b) {
return (a.space != b.space) || (a.channels != b.channels);
}

// Predefined pixel_layout instances, for use as template arguments
// As static constexpr members of class, to make sure they have external linkage,
// required for use as reference template arguments.
struct default_pixel_layouts {
static constexpr pixel_layout rgb{ color_space::rgb, 3 };
static constexpr pixel_layout cymk{ color_space::cymk, 4 };
};

// Definitions for the pixel_layouts
constexpr pixel_layout default_pixel_layouts::rgb;
constexpr pixel_layout default_pixel_layouts::cymk;


// PIXEL TYPE
// Takes pixel_layout reference as non-type template argument.
template<const pixel_layout& Layout>
struct pixel {
static constexpr const pixel_layout& layout = Layout;

// Because layout is constexpr, can use its members (e.g. channels),
// for example as template argument.
// Here size of pixel depends on number of channels in pixel_layout
std::array<std::uint32_t, layout.channels> data;
};

// RGB and CYMK pixel_types as type aliases
using rgb = pixel<default_pixel_layouts::rgb>;
using cymk = pixel<default_pixel_layouts::cymk>;


// IMAGE
// Takes pixel type as template argument.
template<class PixelType>
class image {
public:
using pixel_type = PixelType;
};


// TRANSFORM
// Takes pixel_layouts to transform from/to at runtime. Can for with the predefined
// ones, but also with new ones creates at runtime.
class transform {
private:
const pixel_layout& from_;
const pixel_layout& to_;

public:
transform(const pixel_layout& from, const pixel_layout& to) :
from_(from), to_(to) { }

// Example: function working on an image
template<class Image>
void run(Image& img) {
// Need to make sure that Image's pixel_layout (compile-time) matches
// pixel_layout of the transform (runtime).
if(Image::pixel_type::layout != from_)
std::cout << "Wrong pixel type on input image" << std::endl;
else
std::cout << "transforming..." << std::endl;
}

};



int main() {
image<rgb> rgb_img;
image<cymk> cymk_img;

// Transform from rgb to cymk
transform tr(default_pixel_layouts::rgb, default_pixel_layouts::cymk);
tr.run(rgb_img); // ok
tr.run(cymk_img); // error: input to run() must have rgb pixel_layout

// Creating a new pixel_layout at runtime
pixel_layout custom_layout = { color_space::other, 10 };
transform tr2(custom_layout, default_pixel_layouts::cymk);

return 0;
}

http://coliru.stacked-crooked.com/a/981e1b03b3b815c5

对于在编译时使用 pixel_layout 的用例,需要将不同的可用 pixel_layout 实例实例化为全局静态 constexpr 对象。

pixel_type 然后实例化为不同的类,具体取决于作为模板参数给出的 pixel_layout&

但它们仍然可以在运行时使用。

关于c++ - 以在编译时和运行时都可用的方式在 C++ 中描述像素格式信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34991908/

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