原文
最近在搞iguana
.struct_pb
动态反射功能时,遇见一个奇怪
的问题.
struct person {
std::string name;
int64_t age;
};
REFLECTION(person, name, age);
struct persons {
std::vector<person> list;
};
REFLECTION(persons, list);
//#1
static_assert(iguana::is_public_reflection_v<persons>);
#1
代码是符合期望
的,因为person
和人们
都是iguana
的可反射对象
,is_reflection_v
的实现也比较简单
:
template <typename T, typename = void>
struct is_public_reflection : std::false_type {};
template <typename T>
struct is_public_reflection<
T, std::void_t<decltype(iguana_reflect_members(std::declval<T>()))>>
: std::true_type {};
template <typename T>
constexpr bool is_public_reflection_v = is_public_reflection<T>::value;
void_t
来检查T对象
是否匹配iguana_reflect_members
函数的调用,函数签名如下:
template<typename T>
inline static auto iguana_reflect_members(const T& t);
只要结构
定义了REFLECTION
宏,就一定匹配iguana_reflect_members
调用函数,目前一切正常,但是给结构加一行代码
后就有问题
了.
struct persons {
persons(std::vector<person> s) : list(std::move(s)) {}
std::vector<person> list;//..
};
REFLECTION(persons, list);
给人们
加了一个构造器
,然后这样静态检查
:
static_assert(iguana::is_public_reflection_v<std::vector<person>>);
惊讶
的是通过了该检查
,是的!为什么?因为隐式转换
.
原来可按人们
隐式转换std::vector
,而人们
则是个可反射对象
,所以错误的通过了.
变通
是避免隐式转换
,在构造器前加explicit
,但该方法治标不治本
.
另外或将ADL
函数的参数改成指针
,std::vector
是无法
转换成人们
指针的.但是仍不够
,如果有个从人们
继承的类,继承类指针
可隐式转换
为基类指针
的,仍有漏洞.
最好是用个identity
来包装
一下ADL
参数,这样,外面怎么隐式转换
,也无法转换
到identity
了.
template<typename T>
struct identity{};
template<typename T>
inline static auto iguana_reflect_members(const identity<T>& t);
至此解决问题
,隐式转换
的坑还真不小
,需要特别注意
.
另外预告一下iguana.struct_pb
的动态反射功能
:
1,根据类型名
创建对象实例
2,取对象所有的字段名
3,根据字段名和实例
取置字段的值
.