首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >std::bitset的混合宽度操作

std::bitset的混合宽度操作
EN

Code Review用户
提问于 2019-06-13 17:43:51
回答 1查看 116关注 0票数 9

当我想在我的std::bitset中使用__uint128而不是GCC的D1时,我发现它很难使用,因为没有办法将一个位集扩展或截断到另一个大小。也不能使用不同宽度的位集进行逐位算术(&|^)或比较(==!=)。

我已经确定了我认为应该是std::bitset的一部分的函数,并通过包装标准类来实现它们。为了在不同宽度之间进行转换,我不得不通过std::string,但是(正如注释中所写的),对std::bitset的更新将有一个更直接(且无异常)的路径。

我本可以创建而不是继承std::bitset --这在这里并不是真正值得关注的。请忽略处理my::bitsetstd::bitset不同的机制,并设想它们是一个单一的、更大的类。我最感兴趣的是函数签名是否正确和完整。

请注意(与整数一样),拓宽可以是隐式的,但是收缩操作需要是显式的。大多数明显的重复是为了处理这一区别。

代码语言:javascript
复制
#include 
#include 
#include 
#include 

namespace my {

    template
    struct bitset : public std::bitset
    {
        // forwarding of std::bitset constructors
        bitset()
            : std::bitset{}
        {}

        template
        requires std::is_unsigned_v
        bitset(T n)
            : std::bitset{n}
        {}

        template< class CharT, class Traits, class Alloc >
        explicit bitset(const std::basic_string& str,
                        typename std::basic_string::size_type pos = 0,
                        typename std::basic_string::size_type n =
                        std::basic_string::npos)
            : std::bitset{str, pos, n}
        {
        }

        // Widening and narrowing constructors, to be added to std::bitset

        // widening conversion
        template
        requires (P <= N)
        bitset(const std::bitset& n) noexcept
            : std::bitset{}
        {
            std::size_t i = n.size();
            while (i-- > 0) {
                this->set(i, n.test(i));
            }
        }

        // narrowing conversion
        template
        requires (P > N)
        explicit bitset(const std::bitset& n) noexcept
            : std::bitset{}
        {
            std::size_t i = this->size();
            while (i-- > 0) {
                this->set(i, n.test(i));
            }
        }
    };

    // Deduction guide for my::bitset
    template
    bitset(std::bitset) -> bitset;


    // Free functions to be added to namespace std

    // Deduction guide
    template
    requires std::is_unsigned_v
    bitset(T) -> bitset;


    // comparisons - widen as necessary
    template
    constexpr auto operator==(const bitset& a, const bitset& b)
        requires (N != Q)
    {
        if constexpr (N > Q)
            return a == bitset{b};
        else
            return bitset{a} == b;
    }

    template
    constexpr auto operator!=(const bitset& a, const bitset& b)
    {
        return ! (a == b);
    }

    // bitwise-and produces the narrower type
    // (a specific exception to "doing as the integers do")
    template
    constexpr auto operator&(const bitset& a, const bitset& b)
        requires (N > Q)
    {
        return bitset(a) & b;
    }

    template
    constexpr auto operator&(const bitset& a, const bitset& b)
        requires (N < Q)
    {
        return a & bitset(b);
    }

    // bitwise-and assignment accepts a wider type
    template
    constexpr auto operator&=(bitset& a, const bitset& b)
        requires (N != Q)
    {
        return a &= bitset(b);
    }

    // bitwise-or produces the wider type
    template
    constexpr auto operator|(const bitset& a, const bitset& b)
        requires (N < Q)
    {
        return bitset{a} | b;
    }

    template
    constexpr auto operator|(const bitset& a, const bitset& b)
        requires (N > Q)
    {
        return a | bitset{b};
    }

    template
    constexpr auto& operator|=(bitset& a, const bitset& b)
        requires (N >= Q)
    {
        return a = a | bitset{b};
    }

    // bitwise-xor produces the wider type
    template
    constexpr auto operator^(const bitset& a, const bitset& b)
        requires (N < Q)
    {
        return bitset{a} ^ b;
    }

    template
    constexpr auto operator^(const bitset& a, const bitset& b)
        requires (N > Q)
    {
        return a ^ bitset{b};
    }

    template
    constexpr auto& operator^=(bitset& a, const bitset& b)
        requires (N >= Q)
    {
        return a = a ^ bitset{b};
    }

    template
    requires std::is_unsigned_v
    constexpr auto operator^(const bitset& a, const T& b)
    {
        return a ^ bitset{b};
    }
    template
    requires std::is_unsigned_v
    constexpr auto operator^(const T& a, const bitset& b)
    {
        return bitset{a} ^ b;
    }

}对于上述代码,我有一个简单的编译测试。标记为// new的所有混合宽度操作都不会使用std::bitset进行编译;所有未注释的语句在my::bitset中都很好。注释掉的语句将是错误(因为它们具有不强制转换的收缩转换)。#define NEW_BITSET

int main()
{
#ifdef NEW_BITSET
    using my::bitset;
#else
    using std::bitset;
#endif

    // Lower-case variables are narrow; upper-case are wide

    bitset<32> a{0xFFFF0000u};
    bitset<64> B{a ^ 0xFFFF00u};

    //bitset<32> b = B;         // error
    bitset<32> b{B};            // explicit conversion
    //auto b = bitset<32>{B};   // error

    bitset c = a & B;           // new;  c  is bitset<32>
    bitset D = a | B;           // new;  D  is bitset<64>
    bitset E = a ^ B;           // new;  E  is bitset<64>

    c &= b;                     // no change
    c &= B;                     // new (unlike |= and ^=)
    B &= c;                     // new

    c |= b;                     // no change
    //c |= B;                   // error
    D |= b;                     // new

    c ^= b;                     // no change
    //c ^= B;                   // error
    D ^= b;                     // new
    D &= E;                     // no change
}我可能应该使用Detection成语来断言某些东西不应该有效,但我不得不逐个取消对// error行的注释,以证明它们是错误的。我特别希望在我的混合宽度操作的接口中发现任何错误或遗漏,但我很乐意接受任何批评。
EN

回答 1

Code Review用户

发布于 2019-06-14 07:31:48

一个可能让用户感到惊讶的方面是,运算符&总是缩小匹配类型。这与通常的“做整数所做的”的指导是不同的。

一方面,不要把资源浪费在永远为零的比特上是有道理的。我自己的一个用例是从130位值中提取一些或全部较低的26位位,所以期望26位的结果似乎是合理的。

另一方面,当移动结果时,它可能会捕获用户。这两项职能将产生不同的结果:

代码语言:javascript
复制
auto fun_i(std::uint32_t a, std::uint16_t b) {
    return (a & b) << 16;
}

auto fun_b(my::bitset<32> a, my::bitset<16> b) {
    return (a & b) << 16;
}

总的来说,我认为在转移之前必须明确地扩大范围是在掩盖大量数字时为节省资源而付出的一个公平的代价,但这需要有很好的记录。我重视不同的意见(请在评论中)。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/222236

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档