如何将枚举 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 - 可以是 class
或 enum
.
第三个 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
将调用编译错误。
我正在尝试编写一个可以用作库的通用容器 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 - 可以是 class
或 enum
.
第三个 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
将调用编译错误。