C++标准当前并没有提供反射能力,在yaLanTingLibs中提供了一种反射机制,结合源码对库中使用的编程手法进行简单分析,包括编译期获取结构体成员字段的个数,各个字段的类型;读取结构体字段;
编译期获取结构体字段个数
struct Test {
int32_t v1;
int32_t v2;
int32_t v3;
int32_t v4;
};
Test t {1, 2, 3, 4}; // 完成聚合初始化
Test t {1, 2, 3, 4, 5}; // 编译出错,error: too many initializers for ‘Test’
当初始化个数超过结构体字段个数时则会报错,正是利用这个约束在编译期得到字段个数
template , typename ...Args>
struct IsConstructable : std::false_type {};
template
struct IsConstructable, Args...> : std::true_type {};
template
constexpr size_t MemberCount()
{
if constexpr (IsConstructable::value) {
return Membe服务器托管网rCount();
} else {
return sizeof...(Args);
}
}
static_assert(MemberCount() == 4, "is not equal");
这里结构体中都会int32_t类型,如何支持不同类型?库中引入了AnyType
struct AnyType {
template
operator T() {
return T {};
}
};
template , typename ...Args>
struct IsConstructable : std::false_type {};
template
struct IsConstructable, Args...> : std::true_type {};
template
constexpr size_t MemberCount()
{
if constexpr (IsConstructable::value) {
return MemberCount();
} else {
return sizeof...(Args);
}
}
但对于非aggregate类型则不支持,可以通过std::is_aggregate判断;
编译期获取结构体字段类型
struct Test {
int32_t v1;
int32_t v2;
int32_t v3;
std::string v4;
};
Test t{1, 2, 3, "hello world"};
auto &&[v1, v2, v3, v4] = t;
DBG_LOG("%d %d %d %s", v1, v2, v3, v4.c_str());
通过结构化绑定可以获取到结构体成员字段,由此可得到:
template
constexpr decltype(auto) VisitMember(Object&& obj, Visitor&& vis)
{
constexpr auto count = MemberCount>();
if constexpr (count == 0) {
return vis();
} else if constexpr (count == 1) {
auto &&[v1] = obj;
return vis(v1);
} else if constexpr (count == 2) {
auto &&[v1, v2] = obj;
return vis(v1, v2);
} else if constexpr (count == 3) {
auto &&[v1, v2, v3] = obj;
return vis(v1, v2, v3);
} else if constexpr (count == 4) {
auto &&[v1, v2, v3, v4] = obj;
return vis(v1, v2, v3, v4);
} else if constexpr (count == 5) {
auto &&[v1, v2, v3, v4, v5] = obj;
return vis(v1, v2, v3, v4, v5);
} else if constexpr (count == 6) {
auto &&[v1, v2, v3, v4, v5, v6] = obj;
return vis(v1, v2, v3, v4, v5, v6);
} else if constexpr (count == 7) {
auto &&[v1, v2, v3, v4, v5, v6, v7] = obj;
return vis(v1, v2, v3, v4, v5, v6, v7);
} else if constexpr (count == 8) {
auto &&[v1, v2, v3, v4, v5, v6, v7, v8] = obj;
return vis(v1, v2, v3, v4, v5, v6, v7, v8);
} else if constexpr (count == 9) {
auto &&[v1, v2, v3, v4, v5, v6, v7, v8, v9] = obj;
return vis(v1, v2, v3, v4, v5, v6, v7, v8, v9);
} else if constexpr (count == 10) {
auto &&[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] = obj;
return vis(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10);
}
}
此处举例使用10个字段个数进行说明,通过tuple既可以获取字段类型:
using Types = decltype(VisitMember(Test {服务器托管网}, [](auto&&... args) constexpr {
return std::tuple...> {}; })
);
std::cout ().pretty_name()
输出为:
T type:std::tuple, std::allocator > >
读取结构体字段
VisitMember(Test{1, 2, 3, "hello world"}, [](auto&&... args) {
((std::cout
参考资料
【1】https://github.com/alibaba/yalantinglibs
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: 在Istio中,到底怎么获取 Envoy 访问日志?
Envoy 访问日志记录了通过 Envoy 进行请求 / 响应交互的相关记录,可以方便地了解具体通信过程和调试定位问题。 环境准备 部署 httpbin 服务: kubectl apply -f samples/httpbin/httpbin.yaml 部署 …