如何将枚举 class 包含为 class 模板参数?

How to include enum class as class template arguments?

我正在尝试编写一个可以用作库的通用容器 class。我想用它来实例化 collection 中的每个 object 恰好一次。所以我想传递指向新实例的指针和一个容纳枚举 class 以能够确保所有 object 都是唯一的并且被考虑在内。

在像这样的函数中重复我自己几次之后...

enum class HBeams
{
    HEB100,
    enumSize
};

void HBeam::CreatePredefinedHBeam(std::map<HBeams, HBeam *> & _library, HBeams _key, ushort _width, ushort _height)
{
    if(_library.count(_key) == 0)
    {
        _library.insert(std::pair<HBeams, HBeam *>(_key, new HBeam{ _width, _height } ));
        if(_library.count(_key) == 1)
        {
            Logger::Log(Status::OK, "Created predefined HBeam with ID ", static_cast<int>(_key));
            return;
        }
    }

    Logger::Log(Status::Warning, "Failed to create predefined HBeam with ID ", static_cast<int>(_key));
    return;
}

...我觉得我应该为此创建一个通用容器 class。然而,

// Library.h
template <class T, enum class E>
class Library
{
    std::map<E, T*>  m_entries;

public:
    void  Insert(T* _entry, E _enum);
};

// Library.cpp
template<class T, enum class E>
void Library<T, E>::Insert(T* _entry, E _enum)
{
  ...
}

... 首先告诉我我 必须使用 'enum' 而不是 'enum class',然后我的 模板参数 non-type 模板参数应该是一个表达式。 看来我可以通过在库 class 的 header 中定义所有枚举 classes 来克服这个问题,如下所示:

enum class HBeams
{
    HEB100,
    enumSize
};

template <class T>
class HBeamLibrary
{
    std::map<HBeams, T*>  m_entries;

public:
    void  Insert(T* _entry, HBeams _key);
};

...但是我仍然必须为每个实现手动创建一个 class。我有办法让 "enum class template" 工作吗?

你的 library class 应该是这样的:

// Library.h
template <class T, class E>
class Library
{
    static_assert(std::is_enum<E>::value);

    std::map<E, T*>  m_entries;
public:
    void  Insert(T* entry, E enum)
    {
        // ...
    }
};

用法为:

enum class HBeams {/*..*/};
class HBeam;

Library<HBeam, HBeams> library;

您可以对第二个模板参数做一个简单的条件:

template <class T, class E, class = typename std::enable_if<std::is_enum<E>::value>::type>
class Library
{
    std::map<E, T*>  m_entries;

public:
    void Insert(T* _entry, E _enum) {
        if(m_entries.count(_enum) == 0)
        {
            m_entries.insert(std::pair<E, T*>(_enum, _entry));
            if(m_entries.count(_enum) == 1)
            {
                return;
            }
        }
    }
};

解释:

E - 可以是 classenum.
第三个 class 参数 - 仅当 e 是 enum.

时才合法

示例:

enum class A {
    A,
    B
};
class Test {};
Library<Test, A> l; // The code will compile
Test t;
l.Insert(&t, A::A); // Works just fine

// ----------------

Library<Test, Test> l; // The code won't compile
// Error: "template argument 3 is invalid"

它是如何工作的?

enable_if 声明如下所示:

/// Define a member typedef @c type only if a boolean constant is true.
template<bool, typename _Tp = void>
struct enable_if { }; // no type named `type` is declared as class sub type

// Partial specialization for true.
template<typename _Tp>
struct enable_if<true, _Tp> { // if the condition is true
    typedef _Tp type; // type named `type` is declared as class sub type
};

enable_if 让您有机会在编译时检查条件。如果条件设置为 true,则将调用 true 的偏特化,其中包含名为 type 的子类型。在这种情况下,第三个模板参数将接收一个合法的现有类型,一切都会正常工作。

有趣的情况是 enable_if 条件设置为 false。在这种情况下,此结构将不包含任何名为 type 的子类型,并且任何尝试访问此类型成员的尝试都如:

std::enable_if<false::value>::type

将调用编译错误。