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>();
}