C++ 使用布尔值设置位集的最佳方法

C++ 使用布尔值设置位集的最佳方法,c++,c++11,bitset,C++,C++11,Bitset,假设我有3个booltype值 bool canwalk=true; bool cantalk=false; bool caneat=false; 我想设置一个位集,表示三个 std::bitset<3> foo; 引入一个新的api,它可以为您提供位集在参数中接受的字符串输入 更一般地说,建议使用bool数组或[std::vector][1]删除getString()中的这些变量参数 inline std::string getString(bool canwalk、bool

假设我有3个
bool
type值

bool canwalk=true;
bool cantalk=false;
bool caneat=false;
我想设置一个
位集
,表示三个

std::bitset<3> foo;

引入一个新的api,它可以为您提供位集在参数中接受的字符串输入

更一般地说,建议使用bool数组或
[std::vector][1]
删除getString()中的这些变量参数

inline std::string getString(bool canwalk、bool canTalk、bool canEat)
{
std::stringstream输入;

str您基本上需要一个生成器,它将从布尔集生成一个初始值,并传递给std::bitset的构造函数。您可以在编译时(而不是运行时)通过可变模板执行此操作,如下所示:

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
}
模板
constexpr unsigned long long bitset_value_builder_impl(){return initialValue;}
模板
constexpr无符号长位集\u值\u生成器\u impl(First&&First,Args&&Args){
先回来?

bitset_value_builder_impl<(initialValue |)(1UL遵循Shivendra Agarwal的示例,但使用接收
无符号长
的构造函数,我建议使用以下可变模板函数(更通用)

只有当
std::bitset
的维度不大于
无符号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;
 }
#包括
#包括
模板
无符号长整环(Args…as)
{
使用unused=int[];
无符号long-long-ret{0ULL};

(void)未使用的{0,(retIMHO,类型的初始化

std::bitset<3> foo(canWalk, cantalk, caneat);
该函数可按如下方式使用

std::bitset<3> foo{ getULL(canwalk, cantalk, caneat) };
std::bitset<3> foo{ makeBitSet(canwalk, cantalk, caneat) };
注意,从C++14开始,
makeBitSet()
可以使用返回的
auto
类型

template <typename ... Args>
auto makeBitSet (Args ... as)
 {
   // ...
下面是一个完整的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;
 }
#包括
#包括
模板
std::位集makeBitSet(Args…as)
{
使用unused=bool[];
std::位集ret;
std::size\u t ui{ret.size()};
(void)未使用的{true,(ret.set(--ui,as),true)…};
返回ret;
}
int main()
{
布尔能走{真};
bool-cantalk{false};
布尔·卡奈特{false};
auto-foo=makeBitSet(canwalk、cantalk、caneat);

std::cout很遗憾
std::bitset
没有使用
std::initializer\u list
的构造函数。这可能很危险,但不固定长度是标准的。c样式数组和std::数组都允许这样做。我想知道为什么他们不使用或推荐这种方法来处理std::数组?@GemTaylor:c样式数组具有向后兼容性似乎从以null结尾的字符串中获得了优先权,并且
std::array
是一种简单的类型,它只是c样式数组周围最薄的包装器,它的神奇之处在于它没有构造函数,因此它默认只使用遗留语法构造c样式数组使用构造函数将打破这一魔法。更喜欢
位集.运算符[]
,有时会获得巨大的性能胜利。不确定这有多容易。@MooingDuck-我不知道…但有意义:不是恒定版本的
运算符[]
返回一个
std::bitset::reference
并且以下赋值通过这个类。是:
set()
更好。谢谢。为什么要使用
无符号long-long
作为临时?为什么不创建位集然后分配?@MooingDuck-嗯……我喜欢Shivendra Agarwal的答案,但我发现它有点重;所以我开发了一个轻量级版本;我的另一个答案是“只创建位集然后分配”(是的,我认为这更好)通过字符串强制转换使用了不必要的位集,因为某种原因提供了一个字符串构造函数!另外,我们在构造时使用的是stringstream而不是string,这对于我们可能希望附加字符串的场景来说是非常优化的。
std::bitset<3> foo(canWalk, cantalk, caneat);
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) };
auto foo = makeBitSet(canwalk, cantalk, caneat);
template <typename ... Args>
auto makeBitSet (Args ... as)
 {
   // ...
template <typename ... Args>
auto makeBitSet (Args ... as)
 {
   std::bitset<sizeof...(Args)>  ret;

   std::size_t ui { ret.size() };

   ( ret.set(--ui, as), ... );

   return ret;
 }
#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;
 }