Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
方便的标志处理,所有标志都不能放入64位 我想在C++中创建一个方便的标志处理程序。_C++ - Fatal编程技术网

方便的标志处理,所有标志都不能放入64位 我想在C++中创建一个方便的标志处理程序。

方便的标志处理,所有标志都不能放入64位 我想在C++中创建一个方便的标志处理程序。,c++,C++,通常的想法是使用如下内容: enum class Flag { Foo = 1<<0, Bar = 1<<1, Baz = 1<<2 }; // these operators can be generalized by using template functions with SFINAE Flag operator|(Flag a, Flag b) { return static_cast<Flag>(sta

通常的想法是使用如下内容:

enum class Flag {
    Foo = 1<<0,
    Bar = 1<<1,
    Baz = 1<<2
};

// these operators can be generalized by using template functions with SFINAE
Flag operator|(Flag a, Flag b) {
    return static_cast<Flag>(static_cast<underlying_type>(a)|static_cast<underlying_type>(b));
}
// add other operators here, like &, ^, |=, etc.
enum类标志{

Foo=1只需使用
std::vector
将标志存储为位(按这种方式实现)。如果位字段的大小是固定的,则使用
std::bitset
只需使用
std::vector
将标志存储为位(按这种方式实现)。如果位字段的大小是固定的-请使用
std::bitset

以下是我的想法。这只是一个概念,缺少很多功能(多位标志、其他运算符等),但可以轻松添加

下面是一个用法示例:

enum class Group1 {
    AttrA,
    AttrB,
    AttrC,
};

// count tells to Flags how many entries are there.
// no other boilerplate code is needed
constexpr int count(Group1) {
    return 3;
}

enum class Group2 {
    AttrA,
    AttrB,
};

constexpr int count(Group2) {
    return 2;
}

int main() {
    Flags<Group1, Group2> flags; // flags will have 5 used bits in it
    flags |= Group1::AttrA;
    flags |= Group1::AttrC;

    flags = Group2::AttrB|Group1::AttrA;
}
枚举类组1{
阿特拉,
AttrB,
属性,
};
//count告诉标志有多少个条目。
//不需要其他样板代码
constexpr整数计数(组1){
返回3;
}
枚举类组2{
阿特拉,
AttrB,
};
constexpr整数计数(组2){
返回2;
}
int main(){
Flags Flags;//Flags将包含5个已用位
标志|=Group1::AttrA;
标志|=Group1::AttrC;
flags=Group2::AttrB | Group1::AttrA;
}
以下是解决方案:

#include <type_traits>
#include <cstdint>

namespace Private {

template <typename ...FLAGS>
struct FlagsSize;

template <typename FIRST, typename ...TAIL>
struct FlagsSize<FIRST, TAIL...> {
    static constexpr int value = count(FIRST()) + FlagsSize<TAIL...>::value;
};

template <>
struct FlagsSize<> {
    static constexpr int value = 0;
};

template <typename ELEMENT, typename ...FLAGS>
struct FlagOffset;

template <typename ELEMENT, typename ...FLAGS>
struct FlagOffset<ELEMENT, ELEMENT, FLAGS...> {
    static constexpr int value = 0;
};

template <typename ELEMENT, typename FIRST, typename ...TAIL>
struct FlagOffset<ELEMENT, FIRST, TAIL...> {
    static constexpr int value = count(FIRST()) + FlagOffset<ELEMENT, TAIL...>::value;
};

}

template <typename ...FLAGS>
class Flags {
    public:
        static const std::size_t size = Private::FlagsSize<FLAGS...>::value;
    private:
        std::uint8_t m_storage[(size+7)/8];
    public:
        Flags() {
            clearAll();
        }

        void clearAll() {
            for (std::size_t i=0; i<sizeof(m_storage); i++) {
                m_storage[i] = 0;
            }
        }
        bool get(int index) const {
            return m_storage[index>>3]&(1<<(index&7));
        }
        void set(int index, bool value = true) {
            if (value) {
                m_storage[index>>3] |= 1<<(index&7);
            } else {
                m_storage[index>>3] &= ~(1<<(index&7));
            }
        }

        template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
        bool get(FLAG flag) const {
            return get(Private::FlagOffset<FLAG, FLAGS...>::value+static_cast<std::underlying_type_t<FLAG>>(flag));
        }
        template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
        Flags<FLAG> get() const {
            Flags<FLAG> r;
            for (std::size_t i=0; i<count(FLAG()); i++) {
                r.set(static_cast<FLAG>(i), get(static_cast<FLAG>(i)));
            }
            return r;
        }

        template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
        void set(FLAG flag, bool value) {
            set(Private::FlagOffset<FLAG, FLAGS...>::value+static_cast<std::underlying_type_t<FLAG>>(flag), value);
        }

        template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
        Flags &operator|=(FLAG flag) {
            set(flag, true);
            return *this;
        }
        template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
        Flags &operator|=(const Flags<FLAG> &flags) {
            for (std::size_t i=0; i<count(FLAG()); i++) {
                set(static_cast<FLAG>(i), flags.get(static_cast<FLAG>(i)));
            }
            return *this;
        }

        template <typename ...FLAG>
        Flags &operator=(const Flags<FLAG...> &flags) {
            clearAll();
            (operator|=(flags.template get<FLAG>()), ...);
            return *this;
        }
};

template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
constexpr Flags<FLAG> operator|(FLAG a, FLAG b) {
    Flags<FLAG> f;
    f |= a;
    f |= b;
    return f;
}

template <typename FLAGA, typename FLAGB, typename = std::enable_if_t<std::is_enum_v<FLAGA>&&std::is_enum_v<FLAGB>>>
constexpr Flags<FLAGA, FLAGB> operator|(FLAGA a, FLAGB b) {
    Flags<FLAGA, FLAGB> f;
    f |= a;
    f |= b;
    return f;
}
#包括
#包括
命名空间专用{
模板
结构flagsize;
模板
结构Flagsize{
静态constexpr int value=count(FIRST())+flagsize::value;
};
模板
结构Flagsize{
静态constexpr int值=0;
};
模板
结构FlagOffset;
模板
结构FlagOffset{
静态constexpr int值=0;
};
模板
结构FlagOffset{
静态constexpr int value=count(FIRST())+FlagOffset::value;
};
}
模板
类标志{
公众:
静态常量std::size\u t size=Private::flagsize::value;
私人:
标准:uint8_t m_存储[(大小+7)/8];
公众:
旗子(){
clearAll();
}
void clearAll(){

对于(std::size_t i=0;i>3]&(13]|=13]&=~(1我想到了这个。这只是一个概念,缺少很多功能(多位标志、其他运算符等),但可以轻松添加

下面是一个用法示例:

enum class Group1 {
    AttrA,
    AttrB,
    AttrC,
};

// count tells to Flags how many entries are there.
// no other boilerplate code is needed
constexpr int count(Group1) {
    return 3;
}

enum class Group2 {
    AttrA,
    AttrB,
};

constexpr int count(Group2) {
    return 2;
}

int main() {
    Flags<Group1, Group2> flags; // flags will have 5 used bits in it
    flags |= Group1::AttrA;
    flags |= Group1::AttrC;

    flags = Group2::AttrB|Group1::AttrA;
}
枚举类组1{
阿特拉,
AttrB,
属性,
};
//count告诉标志有多少个条目。
//不需要其他样板代码
constexpr整数计数(组1){
返回3;
}
枚举类组2{
阿特拉,
AttrB,
};
constexpr整数计数(组2){
返回2;
}
int main(){
Flags Flags;//Flags将包含5个已用位
标志|=Group1::AttrA;
标志|=Group1::AttrC;
flags=Group2::AttrB | Group1::AttrA;
}
以下是解决方案:

#include <type_traits>
#include <cstdint>

namespace Private {

template <typename ...FLAGS>
struct FlagsSize;

template <typename FIRST, typename ...TAIL>
struct FlagsSize<FIRST, TAIL...> {
    static constexpr int value = count(FIRST()) + FlagsSize<TAIL...>::value;
};

template <>
struct FlagsSize<> {
    static constexpr int value = 0;
};

template <typename ELEMENT, typename ...FLAGS>
struct FlagOffset;

template <typename ELEMENT, typename ...FLAGS>
struct FlagOffset<ELEMENT, ELEMENT, FLAGS...> {
    static constexpr int value = 0;
};

template <typename ELEMENT, typename FIRST, typename ...TAIL>
struct FlagOffset<ELEMENT, FIRST, TAIL...> {
    static constexpr int value = count(FIRST()) + FlagOffset<ELEMENT, TAIL...>::value;
};

}

template <typename ...FLAGS>
class Flags {
    public:
        static const std::size_t size = Private::FlagsSize<FLAGS...>::value;
    private:
        std::uint8_t m_storage[(size+7)/8];
    public:
        Flags() {
            clearAll();
        }

        void clearAll() {
            for (std::size_t i=0; i<sizeof(m_storage); i++) {
                m_storage[i] = 0;
            }
        }
        bool get(int index) const {
            return m_storage[index>>3]&(1<<(index&7));
        }
        void set(int index, bool value = true) {
            if (value) {
                m_storage[index>>3] |= 1<<(index&7);
            } else {
                m_storage[index>>3] &= ~(1<<(index&7));
            }
        }

        template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
        bool get(FLAG flag) const {
            return get(Private::FlagOffset<FLAG, FLAGS...>::value+static_cast<std::underlying_type_t<FLAG>>(flag));
        }
        template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
        Flags<FLAG> get() const {
            Flags<FLAG> r;
            for (std::size_t i=0; i<count(FLAG()); i++) {
                r.set(static_cast<FLAG>(i), get(static_cast<FLAG>(i)));
            }
            return r;
        }

        template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
        void set(FLAG flag, bool value) {
            set(Private::FlagOffset<FLAG, FLAGS...>::value+static_cast<std::underlying_type_t<FLAG>>(flag), value);
        }

        template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
        Flags &operator|=(FLAG flag) {
            set(flag, true);
            return *this;
        }
        template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
        Flags &operator|=(const Flags<FLAG> &flags) {
            for (std::size_t i=0; i<count(FLAG()); i++) {
                set(static_cast<FLAG>(i), flags.get(static_cast<FLAG>(i)));
            }
            return *this;
        }

        template <typename ...FLAG>
        Flags &operator=(const Flags<FLAG...> &flags) {
            clearAll();
            (operator|=(flags.template get<FLAG>()), ...);
            return *this;
        }
};

template <typename FLAG, typename = std::enable_if_t<std::is_enum_v<FLAG>>>
constexpr Flags<FLAG> operator|(FLAG a, FLAG b) {
    Flags<FLAG> f;
    f |= a;
    f |= b;
    return f;
}

template <typename FLAGA, typename FLAGB, typename = std::enable_if_t<std::is_enum_v<FLAGA>&&std::is_enum_v<FLAGB>>>
constexpr Flags<FLAGA, FLAGB> operator|(FLAGA a, FLAGB b) {
    Flags<FLAGA, FLAGB> f;
    f |= a;
    f |= b;
    return f;
}
#包括
#包括
命名空间专用{
模板
结构flagsize;
模板
结构Flagsize{
静态constexpr int value=count(FIRST())+flagsize::value;
};
模板
结构Flagsize{
静态constexpr int值=0;
};
模板
结构FlagOffset;
模板
结构FlagOffset{
静态constexpr int值=0;
};
模板
结构FlagOffset{
静态constexpr int value=count(FIRST())+FlagOffset::value;
};
}
模板
类标志{
公众:
静态常量std::size\u t size=Private::flagsize::value;
私人:
标准:uint8_t m_存储[(大小+7)/8];
公众:
旗子(){
clearAll();
}
void clearAll(){

对于(std::size_t i=0;i>3]&(13]|=13]&=~(1)你真的有这么多的内存和时间限制,以至于你必须以单个位存储标志吗?你真的不能只使用
enum类:short int int
?系统也需要一组64个标志吗?这些是你的对象可以处于的2^64状态——真的需要那么多的复杂性吗?@blue,是的,可能有一些场景,其中64位是不够的。这很少见,但确实存在。我希望有一个可扩展的解决方案(即,当有超过64个标志时,我不必使用其他解决方案)。此外,正如我所说,这些标志之间可能存在枚举,因此要达到64位并不难。看看一些windows API调用,它们有多少标志。如果不是一位,它就不再是真正的标志。如果要存储任意但固定长度的数据,则需要使用普通的
结构
@MSalters:okay、 我们可以把它叫做别的东西,但问题是一样的。你真的有这么多的内存和时间限制,以至于你必须以单个位存储标志吗?你真的不能只使用
enum类:short int int
?还有一个系统需要一组64个标志吗?这些是你的对象可以处于的2^64个状态——那么多的c确实需要复杂度吗?@blue,是的,可能存在64位不够的情况。这很少见,但确实存在。我希望有一个可扩展的解决方案(即,当有超过64个标志时,我不必使用不同的解决方案)。此外,正如我所说,这些标志之间可能存在枚举,因此要达到64位并不难。看看一些windows API调用,它们有多少标志。如果不是一位,它就不再是真正的标志。如果要存储任意但固定长度的数据,则需要使用普通的
结构
@MSalters:okay、 我们可以把它叫做别的东西,但问题是一样的。