【问题标题】:template argument deduction with strongly-typed enumerations使用强类型枚举的模板参数推导
【发布时间】:2012-03-13 02:56:11
【问题描述】:

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

enum { Cat, Dog, Horse };

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

并将其称为:magic&lt;Cat&gt;(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&lt;Animal, Animal::Cat&gt;(t),这似乎是多余的。

有什么办法可以避免同时输入枚举类和值,缺少

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

【问题讨论】:

  • 为什么不template &lt;EnumClass EnumVal, typename T&gt; bool magic(T &amp;t)?你打算将其他类型的枚举传递给这个函数吗?我不认为你是,因为magical_traits&lt;&gt; 本身只接受一个参数,这没有意义。
  • 嗯,我过度简化了这个例子:是的,这个想法是处理多个枚举类而不重复。很遗憾,因为如果我将 value 作为函数参数传递,它可以很好地推断枚举类,但如果它是模板参数则不能。
  • 事实上,这正是enum classes 的意义所在,每个类型都不同,并且与int 之类的东西特别不同。
  • 真;很遗憾,对于与此处的类型参数相同的非类型参数,推导不起作用。我可以从单个指向成员的参数中推断出包含的类和成员类型,但是对于强类型的枚举参数,没有办法做到这一点。
  • 为什么不只是template &lt;Animal a,typename T&gt; bool magic(T &amp;t)

标签: c++ templates c++17 strong-typing template-argument-deduction


【解决方案1】:

如果你可以使用 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>();
}

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

【讨论】:

  • 从第一次提出问题到现在只用了 5 年!
  • @Useless 哈哈,它出现在问题列表中是因为其他人发布了答案,而我没有查看问题日期;D,但我想有些人可能会觉得它有帮助。跨度>
  • @Sopel: 很有帮助,我之前都没见过template &lt;auto X&gt; 语法!
【解决方案2】:

对不起,我必须告诉你

不可能

获取宏,将其放入一个可怕的命名标头中,并保护它免受您同事的清理脚本的影响。希望最好的。

【讨论】:

  • 是时候做一些宏包装器了……或者,只要我知道不只是我一个人,我可以忍受一点重复。
  • 注意以供将来参考:这个答案对于 C++11 是正确的(这是我问的,以及标记的内容)。我将勾选移至当前接受的答案,因为这是个好消息,而我之前并不知道。
【解决方案3】:

如果您只对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);

但是,正如其他人已经指出的那样,如果你想让它也依赖于类型,它就行不通了。

【讨论】:

    【解决方案4】:

    这个问题有一个accepted answer(已投票)。

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

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

    第二步:客户端代码:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-09
      • 1970-01-01
      相关资源
      最近更新 更多