【问题标题】:C++ - Check if all template arguments are power of 2C++ - 检查所有模板参数是否都是 2 的幂
【发布时间】:2016-10-03 10:53:54
【问题描述】:

我试图找到一种简单的方法来检查作为模板参数传递的参数是否都是 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 解决方案。

【问题讨论】:

  • 你的函数不是模板,参数也不是模板实参。
  • 你能用C++1z,比如here吗?

标签: templates c++11 constexpr variadic


【解决方案1】:

您可以编写一个conjunction trait 来检查参数包中的所有bools 是否都是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>();

Live Demo


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

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

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

【讨论】:

  • 太可爱了!
  • C++1z 提供了非常简单的解决方案,但不幸的是我仅限于使用 C++0x。但是你的结合技巧对我很有效。谢谢。
  • bool_pack off-by-one 就是这样一个黑客。 :p
  • @Yakk 如此华丽的黑客攻击。
【解决方案2】:

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

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 将&lt;true, true, false, true&gt; 与&lt;true, true, true, true&gt; 的序列进行比较,相比之下,将&lt;true, true, true, false, true&gt; 与&lt;true, true, false, true, true&gt; 进行比较的off-by-one hack。在第一种情况下,从类型中很清楚出了什么问题——false——尤其是当你发现右手边总是一包只有true时。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 2010-10-10
    • 1970-01-01
    • 2021-12-26
    相关资源
    最近更新 更多