使用强类型枚举进行模板参数推导

发布于 2025-01-08 07:29:41 字数 707 浏览 4 评论 0原文

如果我有一个普通(弱)枚举,我可以使用它的枚举值作为非类型模板参数,如下所示:

enum { Cat, Dog, Horse };

template <int Val, typename T> bool magic(T &t)
{
    return magical_traits<Val>::invoke(t);
}

将其称为: magic(t)

并尽可能 看,如果我有一个强类型枚举并且不想对枚举类型进行硬编码,我最终会得到:

enum class Animal { Cat, Dog, Horse };

template <typename EnumClass, EnumClass EnumVal, typename T> bool magic(T &t)
{
    return magical_traits<EnumVal>::invoke(t);
}

现在我必须编写: magic(t),这似乎是多余的。

有没有办法避免同时输入枚举类和值,缺少

#define MAGIC(E, T) (magic<decltype(E), E>(T));

If I have a normal (weak) enumeration, I can use its enumerated values as non-type template parameters, like so:

enum { Cat, Dog, Horse };

template <int Val, typename T> bool magic(T &t)
{
    return magical_traits<Val>::invoke(t);
}

and call it as: magic<Cat>(t)

as far as I can see, if I have a strongly-typed enumeration and don't want to hard-code the enumeration type, I end up with:

enum class Animal { Cat, Dog, Horse };

template <typename EnumClass, EnumClass EnumVal, typename T> bool magic(T &t)
{
    return magical_traits<EnumVal>::invoke(t);
}

and now I have to write: magic<Animal, Animal::Cat>(t), which seems redundant.

Is there any way to avoid typing out both the enum class and the value, short of

#define MAGIC(E, T) (magic<decltype(E), E>(T));

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

素罗衫 2025-01-15 07:29:41

,你可以这样做

#include <type_traits>

enum class Animal { Cat, Dog, Horse };

template <typename EnumClass, EnumClass EnumVal> 
void magic_impl()
{
    static_assert(std::is_same_v<EnumClass, Animal>);
    static_assert(EnumVal == Animal::Cat);
}

template <auto EnumVal>
void magic()
{
    magic_impl<decltype(EnumVal), EnumVal>();
}

int main()
{
    magic<Animal::Cat>();
}

如果你可以使用 C++17 demo :
http://coliru.stacked-crooked.com/a/9ac5095e8434c9da

You can do it like this, if you can use C++17

#include <type_traits>

enum class Animal { Cat, Dog, Horse };

template <typename EnumClass, EnumClass EnumVal> 
void magic_impl()
{
    static_assert(std::is_same_v<EnumClass, Animal>);
    static_assert(EnumVal == Animal::Cat);
}

template <auto EnumVal>
void magic()
{
    magic_impl<decltype(EnumVal), EnumVal>();
}

int main()
{
    magic<Animal::Cat>();
}

demo:
http://coliru.stacked-crooked.com/a/9ac5095e8434c9da

游魂 2025-01-15 07:29:41

很抱歉,我必须告诉您,

不可能

将宏放入一个可怕的命名标头中并保护它免受您同事的清理脚本的影响。希望一切顺利。

I'm sorry, I have to tell you that

It is not possible

Take the macro, put it into a scary named header and protect it from your colleague's cleanup script. Hope for the best.

情丝乱 2025-01-15 07:29:41

如果您只对 enum 的值感兴趣,而不是其类型,则应该能够使用 constexpr 函数将值转换为整数,从而避免重复类型名称。

enum class Animal { Cat, Dog, Horse };

template <typename T> constexpr int val(T t)
{
    return static_cast<int>(t);
}

template <int Val, typename T> bool magic(T &t)
{
    return magical_traits<Val>::invoke(t);
}

magic<val(Animal::Cat)>(t);

但是,正如其他人已经指出的那样,如果您想让这也取决于类型,那么它是行不通的。

If you're only interested in the enum's value, and not its type, you should be able to use a constexpr function to convert the value to an integer, avoiding repeating the type name.

enum class Animal { Cat, Dog, Horse };

template <typename T> constexpr int val(T t)
{
    return static_cast<int>(t);
}

template <int Val, typename T> bool magic(T &t)
{
    return magical_traits<Val>::invoke(t);
}

magic<val(Animal::Cat)>(t);

However, as pointed out already by others, if you want to make this depend on the type as well, it will not work.

森林迷了鹿 2025-01-15 07:29:41

此问题有一个已接受的答案(已投票)。

在重构我自己的代码时,我想出了一个更完整的解决方案:

步骤 1:使用我正在编写的代码:

template<typename V, typename EnumClass, EnumClass Discriminator>
class strong_type final // type-safe wrapper for input parameters
{
    V value;
public:
    constexpr explicit strong_type(V x): value{x} {}
    constexpr auto get() const { return value; }
};

步骤 2:客户端代码:

enum class color { red, green, blue, alpha };

// the part OP was asking about:
template<color C>
using color_channel = strong_type<std::uint8_t, color, C>;

using red = color_channel<color::red>; // single argument here
using green = color_channel<color::green>;
using blue = color_channel<color::blue>;
using alpha = color_channel<color::alpha>;

This question has an accepted answer (upvoted).

While refactoring my own code, I figured out a more complete solution:

Step 1: using code I was writing:

template<typename V, typename EnumClass, EnumClass Discriminator>
class strong_type final // type-safe wrapper for input parameters
{
    V value;
public:
    constexpr explicit strong_type(V x): value{x} {}
    constexpr auto get() const { return value; }
};

Step 2: client code:

enum class color { red, green, blue, alpha };

// the part OP was asking about:
template<color C>
using color_channel = strong_type<std::uint8_t, color, C>;

using red = color_channel<color::red>; // single argument here
using green = color_channel<color::green>;
using blue = color_channel<color::blue>;
using alpha = color_channel<color::alpha>;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文