所以我有一个结构体,比如
A
和一个枚举,比如 AE
。我想根据枚举值获取结构成员的类型。我想出了下面的解决方案,这似乎有效。
#include <iostream>
#include <type_traits>
struct A
{
int a;
double b;
};
enum AE
{
TYPE1,
TYPE2
};
template<AE> struct TypeMap;
template<>
struct TypeMap<AE::TYPE1>
{
using type = decltype(A::a);
};
template<>
struct TypeMap<AE::TYPE2>
{
using type = decltype(A::b);
};
int main()
{
TypeMap<AE::TYPE1>::type a;
TypeMap<AE::TYPE2>::type b;
std::cout << typeid(a).name() << '\n';
std::cout << typeid(b).name() << '\n';
}
但是,我必须专门针对每个枚举值和结构成员。有没有更优雅的方法来做到这一点?就像以某种方式使用
TypeMap
或函数设置 type
一样?用例是使用它从 AttributeRetriever 获取基于枚举类型的属性:
if constexpr
上面是涉及继承的类工厂解决方案的替代解决方案,例如:
#include <type_traits>
#include <string>
#include <memory>
#include <iostream>
enum class ErrorCode
{
OK,
FAILURE
};
template <typename ValueType>
class Result
{
// some members and functions
};
struct Attributes
{
uint16_t attribute1;
uint8_t attribute2;
bool attribute3;
//friend std::ostream& operator<<(std::ostream& os, const Attributes& info);
};
enum AttributeType
{
TYPE1,
TYPE2,
TYPE3
};
template<AttributeType> struct TypeMap;
template<>
struct TypeMap<AttributeType::TYPE1>
{
using type = decltype(Attributes::attribute1);
};
template<>
struct TypeMap<AttributeType::TYPE2>
{
using type = decltype(Attributes::attribute2);
};
template<>
struct TypeMap<AttributeType::TYPE3>
{
using type = decltype(Attributes::attribute3);
};
class AttributeRetriever
{
public:
template<AttributeType AT>
Result<typename TypeMap<AT>::type> get()
{
using R = Result<typename TypeMap<AT>::type>;
if constexpr(AT == AttributeType::TYPE1)
{
return R(60);
}
else if (AT == AttributeType::TYPE2)
{
return R(3);
}
else if (AT == AttributeType::TYPE3)
{
return R(false);
}
}
};
int main()
{
AttributeRetriever ar;
std::cout << ar.get<AttributeType::TYPE1>().value() << '\n';
std::cout << static_cast<uint32_t>(ar.get<AttributeType::TYPE2>().value()) << '\n';
std::cout << ar.get<AttributeType::TYPE3>().value() << '\n';
}
class AttributeRetriever
{
public:
using Status = bool;
virtual Status get(Attributes& attributes) = 0;
};
class Attributetype1 : public AttributeRetriever
{
public:
Status get(Attributes& attributes) override
{
attributes.attribute1 = 60;
return true;
}
};
std::unique_ptr<AttributeRetriever> factory(AttributeType at)
{
if (at == TYPE1) return std::make_unique<Attributetype1>();
...
}
将相当于您的
struct Attributes
{
uint8_t attribute2;
uint16_t attribute1;
bool attribute3;
}
。 现有的迂回解决方案如“
magic get”,但通常有两种方法可以做类似的事情。 a) 指向成员的指针。您可以将它们用作模板参数:
Attributes
在这种情况下,您的枚举完全消失:它与字段名称合并,删除重复项。
b) 宏。您可以使用为每个类成员创建结构专业化的宏来声明字段:
template<auto m> struct field_getter;
template<typename T, typename FieldType, FieldType T::*MemberPtr>
struct field_getter<MemberPtr> {
static FieldType get(const T* ptr){ return ptr->*MemberPtr; }
};
(您可以通过更多的宏观工作来自动编号,但这超出了您的问题的范围。)