简体   繁体   English

通过模板参数传递数据,C++

[英]Pass data via template argument, C++

I am thinking about having color spaces structs in my program.我正在考虑在我的程序中使用颜色空间结构。 Now as you can see each color space has its limitations for each of its component.现在您可以看到每个色彩空间对其每个组件都有其限制。 So consider a struct like this.所以考虑这样的结构。

template<typename T>
struct SomeColorSpace{
    T component1,component2,.....; // or std::array<T,N> components, N is compile-time const
};

Now I need somehow define a range so I create a struct.现在我需要以某种方式定义一个范围,所以我创建了一个结构。

template<typename T>
struct Range{

    T min, max;

    // Some constructors initializing min and max...
};

Now I need my color space struct to know what is the range of each of its component.现在我需要我的颜色空间结构来了解其每个组件的范围。 But as you see I can't just hold std::array<Ranges<T>,N> ranges in my struct as the ranges differ from type to type.但正如您所见,我不能只在我的结构中保存std::array<Ranges<T>,N> ranges ,因为范围因类型而异。 As an example consider struct RGB each of the component may be float or unsigned char so when the components are float the ranges of each component becomes [0,1];例如,考虑struct RGB每个组件可能是floatunsigned char ,因此当组件是float时,每个组件的范围变为[0,1]; and when it is unsigned char it is [0,255];当它是 unsigned char 时,它是[0,255]; . . Writing template specialization for each of these case is a solution but instead I want a signature like this.为每种情况编写模板专业化是一种解决方案,但我想要这样的签名。 using RGBFloat = RGB<float,Range<float>...> . using RGBFloat = RGB<float,Range<float>...> I mean I want to pass the ranges via template parameter pack .的意思是我想通过模板参数包传递范围 I know that for instance Range<float>(0,1);我知道例如Range<float>(0,1); is a non-type template parameter so one workaround is to refactor struct Range like this是非类型模板参数,因此一种解决方法是像这样重构struct Range

template<typename T,T _MIN, T _MAX>
struct Range{
    static constexpr T MIN = _MIN;
    static constexpr T MAX = _MAX;
};

So I can pass Range<T,T min, T max> as template parameter pack, but then I have to do keep the pack in a std::tuple (I do not want this either).所以我可以将Range<T,T min, T max>作为模板参数包传递,但是我必须将包保存在std::tuple中(我也不想要这个)。 My question is do you see any other possibility via refactoring the Range struct or something else to have this signature of defining a color space.我的问题是,您是否通过重构Range结构或其他方式看到任何其他可能性,以具有定义颜色空间的这种签名。 using DefineColorSpace = ColorSpace<unsigned char, ranges....> . using DefineColorSpace = ColorSpace<unsigned char, ranges....> I know that C++ 20 has huge refactors for non-type template parameters, but I am using clang and it seem that they do not support that feature yet.我知道C++ 20对非类型模板参数进行了巨大的重构,但我正在使用clang并且似乎它们还不支持该功能。 Any advice can be helpful, thanks)任何建议都会有所帮助,谢谢)

Support for literal classes as non-type template parameter is already in clang trunk. clang 主干中已经支持文字类作为非类型模板参数。 See it live on godbolt :在godbolt上看到它:

template<typename T>
struct Range
{
    T min, max;
};

template<typename T, Range<T> R>
struct SomeColorSpace
{
    static constexpr Range<T> r = R;

    T component1, component2;
};

using Rgb = SomeColorSpace<float, Range<float>{0.0f, 1.0f}>;

auto test()
{
    Rgb color{0.4f, 0.1f};

    float c1 = color.component1;
    float min = Rgb::r.min;

    return Rgb::r.max;
}

So it will arrive soon in clang.所以它很快就会到达 clang。 Until then a possible workaround is to use traits.在此之前,一种可能的解决方法是使用特征。 See it live on godbolt :在godbolt上看到它:

template<class T, class Trait>
struct SomeColorSpace
{
    static constexpr T min = Trait::min;
    static constexpr T max = Trait::max;

    T component1, component2;
};

struct RgbTrait
{
    static constexpr float min = 0.0f;
    static constexpr float max = 1.0f;
};

using Rgb = SomeColorSpace<float, RgbTrait>;

auto test()
{
    Rgb color{0.4f, 0.1f};

    float c1 = color.component1;
    float min = Rgb::min;

    return Rgb::max;
}

Not really clear what you want, as for color, r/g/b/(a) would have same range depending on type.不太清楚你想要什么,至于颜色,r/g/b/(a) 将根据类型具有相同的范围。

So a simple traits allows to map minimum/maximum of float to [0.f,1.f] and std::uint8_t to [0,255] :因此,一个简单的特征允许 map 最小/最大float[0.f,1.f]std::uint8_t[0,255]

template <typename T> struct RangeTraits;

template <> struct RangeTraits<double>
{
    constexpr double min = 0.;
    constexpr double max = 1.;
};
template <> struct RangeTraits<std::uint8_t>
{
    constexpr std::uint8_t min = 0;
    constexpr std::uint8_t max = 255;
};
// ...

And

template <typename T>
struct SomeColorSpace{
    std::array<T, N> components;// N is compile-time constant

// use RangeTraits<T>::min, RangeTraits<T>::max when needed.
};

Another interpretation is that your template parameter are "just" default values for initialization:另一种解释是您的模板参数是初始化的“只是”默认值:

template <typename T, T DefaultMin, T DefaultMax>
struct Range{
    T min = DefaultMin;
    T max = DefaultMax;

    // Some constructors initializing min and max...
};

but those default should be forget afterward但这些默认值应该在之后忘记

So you might be able to do something like:因此,您可能可以执行以下操作:

std::array<Range<std::int8_t>, 2> components{Range<std::int8_t, 0, 127>, Range<std::int8_t, -10, 10>};

Then you might do:然后你可能会这样做:

template <typename T, T...> struct Range;

template <typename T>
struct Range<T>
{
    T min;
    T max;

    Range(T min, T max) : min(min), max(max) {}

    template <T Min, T Max,>
    Range(Range<T, Min, Max>& rhs) : min(rhs.min), max(rhs.max) {}

    Range(Range& rhs) = default;
    // ...
};

template <typename T, T Min, T Max>
struct Range<T, Min, Max>
{
    T min = Min;
    T max = Max;

    Range() = default;
    Range(Range& rhs) = default;

    // Possibly keep constructors of conversion and the one with runtime min/max
    // ...
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM