CPP 枚举作为模板标志
CPP Enums as template flags
我正在尝试重构“std::filesystem::path path = blah; if (path.extension() == ".whatever") load_file(path ) 否则 abort/error".
到目前为止,我已经将我的枚举写成一个位域,其中包含我希望我的应用程序接受的所有文件扩展名,以及 Assets 命名空间中的这个函数:
enum class AcceptedFileExtension : uint32_t {
SCENE = BIT(0),
OBJ = BIT(1),
GLTF = BIT(2),
GLB = BIT(3),
PNG = BIT(4),
JPG = BIT(5),
TTF = BIT(6),
VERT = BIT(7),
FRAG = BIT(8),
SPV = BIT(9),
};
template <AcceptedFileExtension T>
static std::optional<std::filesystem::path> accept(const std::filesystem::path& path)
{
if (to_accepted_extension(path) == T) {
return { path };
}
return {};
}
其中模板类型是我的枚举,本质上定义为位域(每个成员 = 1 << n,例如 AcceptedFileExtension::PNG = 1 << 3)。
我希望此函数接受逻辑上“或”-d 值作为模板,例如:
// AFE = AcceptedFileExtension
auto path_or_nothing = Assets::accept<AFE::PNG | AFE::JPG>(assets_folder_path / images);
我最近阅读了 this post on SO 并尝试为一个新的 API 编写我自己的实现,它将逻辑运算符添加到我编写的枚举 class 中。
但是,问题很明显,这会创建一个值(?),而不是我可以在模板中使用的类型。
这些是内联 constexpr,并实现 or,and,xor。
如果我随后将枚举 class 作为 R 值作为函数的参数(这是调用者应该如何使用它),则会出现另一个问题:
static std::optional<std::filesystem::path> accept(const std::filesystem::path& path, AcceptedFileExtension&& afe)
{
// Does not compile, since "&" does not reduce this to bool but to AFE.
if (to_accepted_extension(path) & afe) {
return { path };
}
return {};
}
我该如何前进?
谢谢。
您可以为枚举编写自己的 operator|
重载。例如
#include<cstdint>
constexpr uint32_t BIT(int i){
return static_cast<uint32_t>(1)<<i;
}
enum class AcceptedFileExtension : uint32_t {
SCENE = BIT(0),
OBJ = BIT(1),
GLTF = BIT(2),
GLB = BIT(3),
PNG = BIT(4),
JPG = BIT(5),
TTF = BIT(6),
VERT = BIT(7),
FRAG = BIT(8),
SPV = BIT(9),
};
constexpr AcceptedFileExtension operator|(
AcceptedFileExtension const& lhs,
AcceptedFileExtension const& rhs
){
return static_cast<AcceptedFileExtension>(
static_cast<uint32_t>(lhs) |
static_cast<uint32_t>(rhs)
);
}
template <AcceptedFileExtension T>
static void accept()
{
}
int main(){
accept<AcceptedFileExtension::PNG | AcceptedFileExtension::JPG>();
}
我正在尝试重构“std::filesystem::path path = blah; if (path.extension() == ".whatever") load_file(path ) 否则 abort/error".
到目前为止,我已经将我的枚举写成一个位域,其中包含我希望我的应用程序接受的所有文件扩展名,以及 Assets 命名空间中的这个函数:
enum class AcceptedFileExtension : uint32_t {
SCENE = BIT(0),
OBJ = BIT(1),
GLTF = BIT(2),
GLB = BIT(3),
PNG = BIT(4),
JPG = BIT(5),
TTF = BIT(6),
VERT = BIT(7),
FRAG = BIT(8),
SPV = BIT(9),
};
template <AcceptedFileExtension T>
static std::optional<std::filesystem::path> accept(const std::filesystem::path& path)
{
if (to_accepted_extension(path) == T) {
return { path };
}
return {};
}
其中模板类型是我的枚举,本质上定义为位域(每个成员 = 1 << n,例如 AcceptedFileExtension::PNG = 1 << 3)。
我希望此函数接受逻辑上“或”-d 值作为模板,例如:
// AFE = AcceptedFileExtension
auto path_or_nothing = Assets::accept<AFE::PNG | AFE::JPG>(assets_folder_path / images);
我最近阅读了 this post on SO 并尝试为一个新的 API 编写我自己的实现,它将逻辑运算符添加到我编写的枚举 class 中。 但是,问题很明显,这会创建一个值(?),而不是我可以在模板中使用的类型。 这些是内联 constexpr,并实现 or,and,xor。
如果我随后将枚举 class 作为 R 值作为函数的参数(这是调用者应该如何使用它),则会出现另一个问题:
static std::optional<std::filesystem::path> accept(const std::filesystem::path& path, AcceptedFileExtension&& afe)
{
// Does not compile, since "&" does not reduce this to bool but to AFE.
if (to_accepted_extension(path) & afe) {
return { path };
}
return {};
}
我该如何前进?
谢谢。
您可以为枚举编写自己的 operator|
重载。例如
#include<cstdint>
constexpr uint32_t BIT(int i){
return static_cast<uint32_t>(1)<<i;
}
enum class AcceptedFileExtension : uint32_t {
SCENE = BIT(0),
OBJ = BIT(1),
GLTF = BIT(2),
GLB = BIT(3),
PNG = BIT(4),
JPG = BIT(5),
TTF = BIT(6),
VERT = BIT(7),
FRAG = BIT(8),
SPV = BIT(9),
};
constexpr AcceptedFileExtension operator|(
AcceptedFileExtension const& lhs,
AcceptedFileExtension const& rhs
){
return static_cast<AcceptedFileExtension>(
static_cast<uint32_t>(lhs) |
static_cast<uint32_t>(rhs)
);
}
template <AcceptedFileExtension T>
static void accept()
{
}
int main(){
accept<AcceptedFileExtension::PNG | AcceptedFileExtension::JPG>();
}