我正在寻找一种优化我写的模板的惯用方法。
我主要关注的是如何正确定义模板参数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;
}
答案 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
错误,因为0
是int
,应该是~(InType)0
。 (1 << bits) - 1
也存在潜在的溢出问题。
答案 1 :(得分:2)
我认为M.M。的答案非常好,而且,在你的情况下,我肯定会使用那里建议的两种替代方案之一。
假设您稍后遇到逻辑的情况,给定 n ,不使用 3 n ,但更复杂的事情,例如 n 2 + 3 n + 1 。或者,也许逻辑不是很复杂,但它可能会发生变化。
第一个选项 - 使用自动推导的auto
,非常简洁,但the omission sometimes makes the declaration less clear。
第二个选项 - 尾随返回类型 - 在某种程度上违反了DRY。
(为了再次澄清,我不认为这些是你的问题或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;
}