位操作- c++中对结构体和类的按位操作

bit manipulation - C++ bitwise operations on structs and classes

本文关键字:位操作 c++ 结构体      更新时间:2023-10-16

我正在开发一个通用遗传算法库,其中每个生物体的染色体是它在内存中的位表示。例如,如果我想让一个有机体发生突变,我就随机地翻转这个物体的比特。

首先,我尝试使用来自c++标准库的bitset类,但是,当转换回对象T时,我唯一的选择是使用to_ullong成员函数,这对于表示大于unsigned long long大小的位数是一个问题。

然后我决定为任何对象T上的按位操作创建一个通用库,这样我就可以直接将这些操作应用到对象本身,而不是先将它们转换为bitset

所以你可以看到我想要实现的,这是一个来自库的函数:

template<typename T>
void flip(T& x, size_t const i)
{
    x ^= 1 << i;
}

它在GA库中是这样使用的:

template<typename T>
void GeneticAlgorithm<T>::mutate(T& organism, double const rate)
{
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_real_distribution<double> dist(0, 1);
    for(size_t i = 0; i < m_nBits; ++i)
        if(dist(mt) <= rate)
            bit::flip(organism, i);
}

这将是非常好的,如果这工作,但现在我得到这个错误消息从vc++ 2015 RC编译器:

严重性代码描述项目文件行错误C2677二进制'^':no找到接受类型为'T'的全局操作符(否则不接受) GeneticAlgorithm GeneticAlgorithm BitManip.hpp 57

如果我纠正^的这个错误,我得到更多的其他操作符。

我没有使用位操作符之前在我的代码,所以我猜这些操作符不应该与任何对象使用?如果是这样,我该如何解决这个问题?

你想要达到的效果可以这样做(参见Peter Schneider的评论):

template<typename T> void flip(T& x, size_t const i) {
    unsigned char* data = reinterpret_cast<unsigned char*>(&x);
    data[i/8] ^= (1 << (i%8));
}

它所做的是将数据x重新解释为字节数组(unsigned char),然后确定应该翻转哪个字节(i/8),然后在字节内的哪个位(i%8)。

注意:另外,在函数的开头添加: 也是安全的。
assert(i < sizeof(T)*8)

我的印象是您还没有完全理解c++提供的面向对象特性。(这在C语言中以数据为中心的编程中并不少见。c++是专门设计来以期望的速度实现这种转换的,并且使其无痛。)

我的建议是将翻转操作封装在一个有机体中,让有机体来处理它。举个例子(未经测试,但可以编译):

#include<climits>  // CHAR_BIT
#include<cstdlib>  // exit()
class string;
void log(const char *);
// inaccessible from the outside
constexpr int NUM_TRAITS = 1000;
constexpr size_t TRAIT_ARR_SZ = (NUM_TRAITS+CHAR_BIT-1)/CHAR_BIT;
class Organism
{ 
    char traits[TRAIT_ARR_SZ];
    int flips[NUM_TRAITS];
    /////////////////////////////////////////////////////////////
    public:
    Organism()  {  /* set traits and flips zero */  }
    // Consider a virtual function if you may derive 
    /** Invert the trait at index traitIndex */
    void flipTrait(int traitIndex)
    {
        if( traitIndex >= NUM_TRAITS ) { log("trait overflow"); exit(1); }
        int charInd = traitIndex / CHAR_BIT;
        int bitInd = traitIndex % CHAR_BIT;
        traits[traitIndex] ^= 1 << bitInd;
        flips[traitIndex]++;
    }
    // Organisms can do so much more!
    void display();
    void store(string &path);
    void load(string &path);
    void mutate(float traitRatio);
    Organism clone();
};