设置带有布尔值的比特集的最佳方法

best way to set a bitset with boolean values

本文关键字:最佳 方法 布尔值 设置      更新时间:2023-10-16

假设我有3个 bool类型值

bool canwalk=true;
bool cantalk=false;
bool caneat=false;

我想设置一个表示三个

bitset
std::bitset<3> foo;

如何使用布尔值构建bitset?我想做这样的事情

 std::bitset<3> foo(canWalk,cantalk,caneat); //giving me 100

遵循Shivendra agarwal的示例,但是使用接收unsigned long long的构造器,我提出了以下variadic模板函数(更通用)

template <typename ... Args>
unsigned long long getULL (Args ... as)
 {
   using unused = int[];
   unsigned long long ret { 0ULL };
   (void) unused { 0, (ret <<= 1, ret |= (as ? 1ULL : 0ULL), 0)... };
   return ret;
 }

允许foo的初始化如下

std::bitset<3> foo{ getULL(canwalk, cantalk, caneat) };

仅当std::bitset的尺寸不是unsigned long long中的位数(使用3肯定是安全的)。

以下是一个完整的工作示例

#include <bitset>
#include <iostream>
template <typename ... Args>
unsigned long long getULL (Args ... as)
 {
   using unused = int[];
   unsigned long long ret { 0ULL };
   (void) unused { 0, (ret <<= 1, ret |= (as ? 1ULL : 0ULL), 0)... };
   return ret;
 }
int main()
 {
   bool canwalk=true;
   bool cantalk=false;
   bool caneat=false;
   std::bitset<3> foo{ getULL(canwalk, cantalk, caneat) };
   std::cout << foo << std::endl;
 }

imho,类型的初始化

std::bitset<3> foo(canWalk, cantalk, caneat);

是危险的(容易出错),因为要求std::bitset的模板参数(示例中的3)与初始化的参数数相对应。

我提出了" make"函数的创建(遵循std::pair()std::tuple()std::make_unique()std::make_shared的合并示例,其中的类型和参数数量修复了返回的类型。

所以我提出了以下makeBitSet()函数,该功能返回 std::bitset<N>,其中 N是参数的数字

template <typename ... Args>
std::bitset<sizeof...(Args)> makeBitSet (Args ... as)
 {
   using unused = bool[];
   std::bitset<sizeof...(Args)>  ret;
   std::size_t ui { ret.size() };
   (void) unused { true, (ret.set(--ui, as), true)... };
   return ret;
 }

该函数可以如下使用

std::bitset<3> foo{ makeBitSet(canwalk, cantalk, caneat) };

,但(更好,恕我直言),使用C 11 auto

auto foo = makeBitSet(canwalk, cantalk, caneat);

观察,从C 14开始,makeBitSet()可以使用返回的auto

template <typename ... Args>
auto makeBitSet (Args ... as)
 {
   // ...

避免烦人的std::bitset<sizeof...(Args)>冗余。

此外,从C 17开始,您可以使用模板折叠,然后丢弃unused阵列(以及相应的using声明),makeBitSet()可以简化为[编辑:修改:改善性能,遵循建议,来自Mooing Duck(谢谢!)]

template <typename ... Args>
auto makeBitSet (Args ... as)
 {
   std::bitset<sizeof...(Args)>  ret;
   std::size_t ui { ret.size() };
   ( ret.set(--ui, as), ... );
   return ret;
 }

以下是完整的工作C 11示例

#include <bitset>
#include <iostream>
template <typename ... Args>
std::bitset<sizeof...(Args)> makeBitSet (Args ... as)
 {
   using unused = bool[];
   std::bitset<sizeof...(Args)>  ret;
   std::size_t ui { ret.size() };
   (void) unused { true, (ret.set(--ui, as), true)... };
   return ret;
 }
int main()
 {
   bool canwalk { true  };
   bool cantalk { false };
   bool caneat  { false };
   auto foo = makeBitSet(canwalk, cantalk, caneat);
   std::cout << foo << std::endl;
 }

引入一个新的API,可以为您提供bitset在参数中接受的字符串输入。

要更通用,建议使用bool数组或 [std::vector<bool>][1]在getTring()

中摆脱这些变量参数
inline std::string getString(bool canwalk, bool canTalk, bool canEat)
{
std::stringstream input;
str << canwalk?1:0 << cantalk?1:0 << caneat?1:0;
return input.str();
}

现在可以将bitset定义为:

std::bitset<3> foo (getString(canwalk, canTalk, canEat));

您基本上需要一个构建器,该构建器将从布尔设置中构建一个初始值,以传递给std :: bitset的构造函数。您可以在编译时间(而不是运行时)通过variadic模板进行此操作,例如:

template <unsigned long long initialValue> 
constexpr unsigned long long bitset_value_builder_impl() { return initialValue; }
template <unsigned long long initialValue, typename First, typename ... Args>
constexpr unsigned long long bitset_value_builder_impl(First &&first, Args &&...args) {
    return first ? 
        bitset_value_builder_impl< (initialValue | (1UL<<sizeof...(args)) ), Args...>(std::forward<Args>(args)...) :
        bitset_value_builder_impl< (initialValue & ~(1UL<<sizeof...(args)) ), Args...>(std::forward<Args>(args)...);
}
template <typename First, typename ... Args>
constexpr unsigned long long bitset_value_builder(First &&first, Args &&...args) {   
    return bitset_value_builder_impl<0, First, Args...>(std::forward<First>(first), std::forward<Args>(args)...);
}
int main()
{
    bool canwalk=true;
    bool cantalk=false;
    bool caneat=false;    
    std::bitset<3> bits{bitset_value_builder(canwalk, cantalk, caneat)};
    std::cout << bits << std::endl; //100
}