英文:
Change default value initialization of scoped enum in C++ 20?
问题
In C++20, it's not possible to change the behavior of default value initialization of a scoped enum directly through language features. Scoped enums are designed to have stricter type safety, and they will always initialize to one of their enumerator values, not an arbitrary value like MyEnum::No
in your example.
You can, however, create a wrapper class, as you've attempted in your code, to achieve a similar effect. Your current approach is on the right track, but you need to make some adjustments to make it work as expected. Specifically, you want to ensure that your wrapper class acts like a real scoped enum.
Here's an updated version of your code that should help you achieve your desired behavior:
#include <iostream>
using MyEnumRootType = unsigned int;
enum class EMyEnum : MyEnumRootType {
Yes = 0x1,
No = 0x2
};
template <typename Enum, Enum DefaultValue>
class EnumWrapper {
public:
EnumWrapper() : value_(DefaultValue) {}
EnumWrapper& operator=(Enum e) { value_ = e; return *this; }
operator Enum() const { return value_; }
private:
Enum value_;
};
constexpr EMyEnum MyEnumNo = EMyEnum::No; // Define a constant for MyEnum::No
int main() {
EnumWrapper<EMyEnum, MyEnumNo> a;
EnumWrapper<EMyEnum, MyEnumNo> b = EMyEnum::Yes; // This will work now
}
In this updated code, we define a constant MyEnumNo
that represents the default value of EMyEnum::No
. This allows you to use MyEnumNo
as the default value for your wrapper class. Now, when you create a MyEnum
variable without specifying a value, it will be initialized with MyEnum::No
.
英文:
Is it possible to change the behavior of default value initialization of a scoped enum in C++ 20 ?
For exemple, in the following code, I'd like that a MyEnum
variable to be initialized automaticatly with MyEnum::No
when declared with MyEnum myValue{};
using MyEnumRootType = unsigned int;
using MyEnum = enum class EMyEnum: MyEnumRootType {
Yes = 0x1,
No = 0x2
};
int main() {
const MyEnum myValue{}; // <- 0
std::cout << static_cast<MyEnumRootType>(myValue);
}
edit:
I'v tried to write a wrapper like Benjamin Buch suggested (thanks).
I'm using template because I want it to be reusable.
I managed to handle a default value but I'm struggling to make it act like a real scoped enum (last line of main doesn't compile).
#include <concepts>
using MyEnumRootType = unsigned int;
enum class EMyEnum: MyEnumRootType {
Yes = 0x1,
No = 0x2
};
template<typename T>
concept ScopedEnum = std::is_enum_v<T> && !std::is_convertible_v<T, int>;
template<typename Enum, auto DefaultValue>
requires ScopedEnum<Enum>
class EnumWrapper{
public:
EnumWrapper(): value_(DefaultValue) {}
EnumWrapper& operator=(Enum e) { value_ = e; return *this; }
operator Enum() const { return value_; }
private:
Enum value_;
};
using MyEnum = EnumWrapper<EMyEnum, EMyEnum::No>;
int main() {
MyEnum a{};
MyEnum b = MyEnum::Yes; // how can I make this works ?
}
Can I do something like this in a template https://en.cppreference.com/w/cpp/language/enum#Using-enum-declaration ?
答案1
得分: 3
这对于枚举来说是不可能的直接操作的(除非你愿意将No
的值更改为0x0
)。枚举不是类类型(即使在enum class
中有class
关键字),因此你无法像在类的成员函数/构造函数/析构函数等中那样影响它们的行为。
相反,你需要创建一个类包装器,在其中你可以定义一个默认构造函数来执行你想要的操作。
英文:
That's not possible directly for an enumeration (except if you are willing to change the value of No
to 0x0
). Enumerations are not class types (even if there is class
in enum class
), so you can't affect their behavior like you can with member functions/constructors/destructors/etc of classes.
Instead you'll have to make a class wrapper around it in which you can define a default constructor to do whatever you want.
答案2
得分: 2
只有通过编写包装类才能实现这种行为。使用 using enum
可以通过包装类直接访问枚举的值。定义一个枚举类型的数据成员和一个用于该类型的强制类型转换操作符。
using MyEnumRootType = unsigned int;
enum class EMyEnum: MyEnumRootType {
Yes = 0x1,
No = 0x2
};
struct MyEnum {
using enum EMyEnum;
constexpr operator EMyEnum() const noexcept {
return value;
}
EMyEnum value = No;
};
int main() {
constexpr MyEnum myValue{};
static_assert(myValue != MyEnum::Yes);
static_assert(myValue == MyEnum::No);
static_assert(myValue != EMyEnum{});
}
英文:
It is only possible to write a wrapper class to achieve this behavior. Use using enum
to address the values of your enumeration directly via the wapper class. Define a data member of the enumeration type and a cast operator for this type.
using MyEnumRootType = unsigned int;
enum class EMyEnum: MyEnumRootType {
Yes = 0x1,
No = 0x2
};
struct MyEnum {
using enum EMyEnum;
constexpr operator EMyEnum() const noexcept {
return value;
}
EMyEnum value = No;
};
int main() {
constexpr MyEnum myValue{};
static_assert(myValue != MyEnum::Yes);
static_assert(myValue == MyEnum::No);
static_assert(myValue != EMyEnum{});
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论