我试图找到一种简单的方法来检查作为模板参数传递的参数是否都是2的幂。我在网站上找到了一个小问题,我有这个:
constexpr bool isPowerOf2(size_t value){
return !(value == 0) && !(value & (value - 1));
}
这适用于单个值,但将此应用于多个参数看起来很难看。
static_assert(isPowerOf2(Arg1), "Argument must be a power of 2");
static_assert(isPowerOf2(Arg2), "Argument must be a power of 2");
static_assert(isPowerOf2(Arg3), "Argument must be a power of 2");
如果我能让它看起来像arePowersOf2(Arg1,Arg2,Arg3),那会更好,但是我在模板魔术方面并不是很先进。所以我的问题是:有一种简单的方法吗?我更喜欢constexpr C ++ 11解决方案。
答案 0 :(得分:7)
您可以编写conjunction
特征,检查参数包中的所有bool
是否为true
。此示例使用@Columbo' bool_pack
技巧:
template <bool...> struct bool_pack{};
template <bool... bools>
struct conjunction : std::is_same<bool_pack<true, bools...>,
bool_pack<bools..., true>>
{};
template <size_t... Args>
constexpr bool arePowerOf2() {
return conjunction<isPowerOf2(Args)...>::value;
}
然后你就这样称呼它:
arePowerOf2<Args...>();
arePowerOf2<Arg1, Arg2, Arg3>();
在C ++ 1z中,您可以使用fold expressions:
template <size_t... Args>
constexpr bool arePowerOf2() {
return (... && isPowerOf2(Args));
}
C ++ 1z也会获得std::conjunction
,这与上面的版本略有不同。
答案 1 :(得分:1)
一包bool是bools的整数序列:
template<bool...Bs>using bools = std::integer_sequence<bool, Bs...>;
这些可以帮助您创建指定长度的true, true, true
序列:
template<std::size_t...Is>
constexpr bools<(Is,true)...> make_trues_f( std::index_sequence<Is...> ) {
return {};
}
template<std::size_t N>
using make_trues_t = decltype( all_true_f( std::make_index_sequence<N>{} ) );
template<class...Ts>
using make_trues_for_t = make_trues_t<sizeof...(Ts)>;
给你:
static_assert(
std::is_same<
bools<isPowerOf2(Args)...>,
make_trues_for_t<Args...>
>::value, "Argument must be a power of 2"
);
或
template<class...Args>
constexpr std::is_same<
bools<isPowerOf2(Args)...>,
make_trues<sizeof...(Args)>
>
all_power_of_2() { return {}; }
我,当我在类型计算级别知道答案时,我甚至喜欢从constexpr
函数返回类型。
作为奖励,失败的比较更明确的是什么,而不是一个一个黑客。 is_same
将<true, true, false, true>
与<true, true, true, true>
的序列进行比较,与将<true, true, true, false, true>
与<true, true, false, true, true>
进行比较的逐个黑客进行比较。在第一种情况下,从类型中可以清楚地看出出了什么问题 - false
- 尤其是当您发现右侧总是只有true
时。