用于根据其他参数计算模板参数的惯用方法

时间:2016-10-01 06:28:57

标签: c++ c++14

我正在寻找一种优化我写的模板的惯用方法。

我主要关注的是如何正确定义模板参数n并将其用作返回参数,而用户不得覆盖它。

我也愿意接受有关如何以惯用的C ++ 14方式编写此模板的其他建议。

template<
  typename InType=uint32_t,
  typename OutType=float,
  unsigned long bits=8,
  unsigned long n=(sizeof(InType) * 8) / bits
>
std::array<OutType,n> hash_to_color(InType in) noexcept {    
  InType mask = ~0;
  mask = mask << bits;
  mask = ~mask;
  std::array<OutType,n> out;
  auto out_max = static_cast<OutType>((1 << bits) - 1);
  for (auto i = 0; i < n; i++) {
    auto selected = (in >> (i * bits)) & mask;
    out[i] = static_cast<OutType>(selected) / out_max;
  }
  return out;
}

2 个答案:

答案 0 :(得分:3)

关于n模板参数,可以使用auto作为C ++ 14中的返回类型来避免它。以下是该原则的一个更简单的例子:

template<int N>
auto f()
{
    constexpr int bar = N * 3;   
    std::array<int, bar> foo;
    return foo;
}

当然,数组模板参数的计算必须是常量表达式。

另一个选项(与C ++ 11兼容)是trailing-return-type:

template<int N>
auto f() -> std::array<int, N * 3>
{

这比使用C ++ 14允许从return语句中返回类型推导更加冗长。

注意:代码中的~0错误,因为0int,应该是~(InType)0(1 << bits) - 1也存在潜在的溢出问题。

答案 1 :(得分:2)

我认为M.M。的答案非常好,而且,在你的情况下,我肯定会使用那里建议的两种替代方案之一。

假设您稍后遇到逻辑的情况,给定 n ,不使用 3 n ,但更复杂的事情,例如 n 2 + 3 n + 1 。或者,也许逻辑不是很复杂,但它可能会发生变化。

(为了再次澄清,我不认为这些是你的问题或M.M的回答中的重大问题。)

因此,第三种选择是将逻辑分解为constexpr函数:

#include <array>

constexpr int arr_size(int n) { return n * n + 3 * n + 1; }

由于它是constexpr,因此可用于实例化模板:

template<int N>
std::array<int, arr_size(N)> f() {
    return  std::array<int, arr_size(N)>();
}

请注意,现在该函数具有显式返回类型,但arr_size的逻辑只出现一次。

你可以像往常一样使用它:

int main() {
    auto a = f<10>();
    a[0] = 3;
}