mr_*_*r_T 8 c++ enums templates c++11
这是C#中可能的(参见如何将枚举转换为类型),但我想知道如何在C++ 11中实现它?
可能的代码框架(也显示我的预期用途)将是:
// classify.h (part of public API)
// definitions of classes A, B, C cannot be exposed, only a list of names
// (some names might even refer to the same type of object)
enum EAllowedTypes { eA, eB, eC };
class Entity;
bool classifyEntityAs(const Entity& ent, EAllowedTypes type);
Run Code Online (Sandbox Code Playgroud)
_
// classify.cpp
#include "A.h" // defines class A (derived from a common base class)
#include "BC.h" // defines class BC (derived from a common base class)
template <typename T>
bool classify(const Entity &)
{
/* some implementation, with possible specializations */
}
// how to implement this kind of vector/map from enum(int) to existing classes
static const std::vector enumToType</*ClassType*/> =
{
/* eA */ class A,
/* eB */ class BC,
/* eC */ class BC
};
bool classifyEntityAs(cont Entity& ent, EAllowedTypes type)
{
return classify<enumToType[type]>(ent);
}
Run Code Online (Sandbox Code Playgroud)
基于注释的一些澄清:1)classify.h是公共API的一部分(对于第三方/其他公司),因此,在编译时无法识别类型.然而,为EAllowedTypes中的所有类型编译模板没有问题.EAllowedTypes主要用于与客户端进行通信,并允许将来更改内部数据类型(无需更改公共API),因此无法保证一对一映射.2)实体不是A,B,BC等中任何一个的基类.它只是一个通用的对象,我们想要将它与A,B或C分类相关联.A,B等的实现细节.附加应该保持隐藏.
您可以执行以下操作:
template <EAllowedTypes e, typename T>
struct cl {
static const decltype(e) value = e;
using type = T;
};
template <typename...>
struct classifier;
template <>
struct classifier<> {
static bool classify(const Entity& ent, EAllowedTypes type) {
throw std::logic_error("Whatever... ");
}
};
template <typename T, typename... Args>
struct classifier<T, Args...> {
static bool classify(const Entity& ent, EAllowedTypes type) {
return type == T::value ?
::classify<typename T::type>(ent)
: classifier<Args...>::classify(ent, type);
}
};
bool classifyEntityAs(const Entity& ent, EAllowedTypes type) {
return classifier<cl<eA, A>, cl<eB, BC>, cl<eC, BC>>::classify(ent, type);
}
Run Code Online (Sandbox Code Playgroud)
这将要求您在cl<eX, X>每次要添加新的可能类时添加一个新类。这基本上是一个“递归” switch,可能会被编译器优化为简单的switch1。这里的想法是enum使用cl结构将值与其类联系起来。
如果要存储cl外部列表,可以执行以下操作:
using enumToType = std::tuple<cl<eA, A>, cl<eB, BC>, cl<eC, BC>>;
template <size_t... Idx>
bool classifyEntityAs(const Entity& ent, EAllowedTypes type,
std::index_sequence<Idx...>) {
return classifier<std::tuple_element_t<Idx, enumToType>...>::classify(ent, type);
}
bool classifyEntityAs(const Entity& ent, EAllowedTypes type) {
return classifyEntityAs(ent, type,
std::make_index_sequence<std::tuple_size<enumToType>{}>{});
}
Run Code Online (Sandbox Code Playgroud)
然后你只需要修改enumToType(我在std::tuple这里使用,但你可以有一个只包含类型的自定义结构)的定义。
1这段代码基本上等价于:
switch (type) {
case eA: return classify<A>(ent);
case eB: return classify<BC>(ent);
case eC: return classify<BC>(ent);
default: throw std::logic_error("Whatever... ");
}
Run Code Online (Sandbox Code Playgroud)
没有办法直接按照你的意愿去做,因为 c++ 不支持反射机制,而且我认为它至少在一段时间内不会改变......但是......如果你知道你的类型应该支持哪些类型分类器,您可以根据您的用例场景调整以下代码:
#include <map>
#include <memory>
#include <iostream>
enum EAllowedTypes { eA, eB, eC };
struct A {
void run() {
std::cout << "A::run() invoked" << std::endl;
}
};
struct B {
void run() {
std::cout << "B::run() invoked" << std::endl;
}
};
struct C {
void run() {
std::cout << "C::run() invoked" << std::endl;
}
};
struct ITypeWrapper {
virtual void run() = 0;
};
template <class T>
struct TypeWrapper: ITypeWrapper {
void run() {
T t;
t.run();
}
};
template <EAllowedTypes AT, class Type>
struct Mapper { };
template <class... Mappers>
struct Classifier;
template <EAllowedTypes... ATs, class... Types>
struct Classifier<Mapper<ATs, Types>...> {
static std::map<EAllowedTypes, std::shared_ptr<ITypeWrapper>> m;
};
template <EAllowedTypes... ATs, class... Types>
std::map<EAllowedTypes, std::shared_ptr<ITypeWrapper>> Classifier<Mapper<ATs, Types>...>::m = { { ATs, std::make_shared<TypeWrapper<Types>>() }... };
using ABCClassifier = Classifier<Mapper<eA, A>, Mapper<eB, B>, Mapper<eC, C>>;
int main() {
ABCClassifier::m[eA]->run();
}
Run Code Online (Sandbox Code Playgroud)
输出:
A::run() 被调用
| 归档时间: |
|
| 查看次数: |
316 次 |
| 最近记录: |