【问题标题】:Idiomatic way to calculate template parameter depending on other parameters根据其他参数计算模板参数的惯用方法
【发布时间】:2017-02-09 18:01:18
【问题描述】:

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

我主要关心的是如何正确定义模板参数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;
}

【问题讨论】:

  • 如果你想确保用户不会覆盖它,也许你可以static_assert它是正确的值?

标签: c++ c++14


【解决方案1】:

关于n模板参数,你可以通过在C++14中使用auto作为返回类型来避免它。下面是一个更简单的原理示例:

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 &lt;&lt; bits) - 1 也有潜在的溢出问题。

【讨论】:

  • 谢谢。这很有帮助。我在问题代码中删除了一些static_assert,以确保位不会被static_assert(bits &lt; sizeof(OutType) * 8) 溢出
【解决方案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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-06
    • 2016-08-07
    相关资源
    最近更新 更多