【问题标题】:Pass data via template argument, C++通过模板参数传递数据,C++
【发布时间】:2020-12-13 02:51:14
【问题描述】:

我正在考虑在我的程序中使用 color spaces 结构。现在您可以看到每个色彩空间对其每个组件都有其限制。所以考虑这样的结构。

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

现在我需要以某种方式定义一个范围,以便创建一个结构。

template<typename T>
struct Range{

    T min, max;

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

现在我需要我的颜色空间结构来了解其每个组件的范围。但正如你所见,我不能只在我的结构中保留std::array&lt;Ranges&lt;T&gt;,N&gt; ranges,因为范围因类型而异。例如,考虑struct RGB,每个组件可能是floatunsigned char,因此当组件为float 时,每个组件的范围变为[0,1];,当它是无符号字符时,它是[0,255];。为每种情况编写模板专业化是一种解决方案,但我想要这样的签名。 using RGBFloat = RGB&lt;float,Range&lt;float&gt;...&gt;。我的意思是我想通过模板参数包传递范围。我知道例如Range&lt;float&gt;(0,1); 是一个非类型模板参数,所以一种解决方法是像这样重构struct Range

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

所以我可以将Range&lt;T,T min, T max&gt; 作为模板参数包传递,但我必须将包保存在std::tuple 中(我也不想要这个)。我的问题是您是否通过重构 Range 结构或其他方式看到任何其他可能性以具有定义颜色空间的签名。 using DefineColorSpace = ColorSpace&lt;unsigned char, ranges....&gt;。我知道C++ 20 对非类型模板参数进行了巨大的重构,但我正在使用clang 并且似乎他们do not support 还具有该功能。 任何建议都会有所帮助,谢谢)

【问题讨论】:

    标签: c++ templates range variadic-templates parameter-pack


    【解决方案1】:

    支持作为非类型模板参数的文字类已经在 clang 主干中。见live on 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;
    }
    

    所以它很快就会在铿锵声中到达。在此之前,一种可能的解决方法是使用特征。见live on 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;
    }
    

    【讨论】:

      【解决方案2】:

      不太清楚你想要什么,至于颜色,r/g/b/(a) 根据类型会有相同的范围。

      因此,一个简单的特征允许将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;
      };
      // ...
      

      template <typename T>
      struct SomeColorSpace{
          std::array<T, N> components;// N is compile-time constant
      
      // use RangeTraits<T>::min, RangeTraits<T>::max when needed.
      };
      

      另一种解释是您的模板参数“只是”用于初始化的默认值:

      template <typename T, T DefaultMin, T DefaultMax>
      struct Range{
          T min = DefaultMin;
          T max = DefaultMax;
      
          // Some constructors initializing min and max...
      };
      

      但那些默认值应该在之后忘记

      所以你也许可以这样做:

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

      那么你可能会这样做:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-26
        • 2016-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-30
        相关资源
        最近更新 更多