Home > Mobile >  CPP Enums as template flags
CPP Enums as template flags

Time:03-15

I'm trying to refactor an entire codebase of "std::filesystem::path path = blah; if (path.extension() == ".whatever") load_file(path) else abort/error".

Thus far, I've written my enum as a bitfield with all the file extensions I wish my application to accept, and this function in the Assets namespace:

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 {};
}

where the template type is my enum, defined as a bitfield essentially (Each member is = 1 << n, say for example AcceptedFileExtension::PNG = 1 << 3).

I would like this function to accept logically "or"-d values as the template, e.g:

// AFE = AcceptedFileExtension
auto path_or_nothing = Assets::accept<AFE::PNG | AFE::JPG>(assets_folder_path / images);

I recently read this post on SO and tried to write my own implementation for a new API, which added the logical operators to the enum class I'd written. However, the problem is obvious, this creates a value (?) and not a type which I can use in templates. These are inline constexpr, and implements or, and, xor.

If I then make the enum class into a parameter for the function as an R-value (which is how the caller should use it), another issue arises:

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 {};
}

How do I move forward?

Thank you.

CodePudding user response:

You can write your own overload of operator| for your enum. E.g.

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