C++ - 检查是否所有模板参数都是 2 的幂

C++ - Check if all template arguments are power of 2

我正在尝试找到一种简单的方法来检查作为模板参数传递的参数是否都是 2 的幂。我在网站上找到了一个 bithack,我有这个:

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 解决方案。

您可以编写一个 conjunction 特征来检查参数包中的所有 bool 是否都是 true。此示例使用 @Columbobool_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>();

Live Demo


在 C++1z 中,您可以为此使用 fold expressions

template <size_t... Args>
constexpr bool arePowerOf2() {
    return (... && isPowerOf2(Args));
}

C++1z 也将得到 std::conjunction,只是与上面的版本略有不同。

一包布尔值是布尔值的整数序列:

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 函数返回类型。

作为奖励,失败的比较更清楚是预期的,而不是一个差一个 hack。 is_same 比较 <true, true, false, true><true, true, true, true> 的序列,而 off-by-one hack 比较 <true, true, true, false, true><true, true, false, true, true>。在第一种情况下,从类型中可以清楚地看出哪里出了问题——false——尤其是当你发现右侧总是一包只有 true.[=23= 时]