【发布时间】:2013-09-26 08:58:47
【问题描述】:
我相当熟悉不涉及宏魔法的标准元编程解决方案(例如C++11 ways of finding if a type has member function or supports operator?)。但是,我有一个涉及以下便利宏的用例(当然,对于 StackOverflow 进行了极大的简化,但想象一下这是用于序列化之类的)......
#define START(type) do { typedef type current; const char typeName[] = #type
#define OUTPUT(fieldname) \
printf("type of %s.%s is %s\n", #type, #fieldname, \
std::is_same<decltype(std::declval<current>().fieldname),int> ? "int" : "string")
#define END() } while (0)
struct Foo { int i; char *j; char *k; };
struct Bar { char *x; int y; };
START(Foo);
OUTPUT(i); // type of Foo.i is int
OUTPUT(j); // type of Foo.j is string
OUTPUT(k); // type of Foo.k is string
END();
START(Bar);
OUTPUT(x); // type of Bar.x is string
OUTPUT(y); // type of Bar.y is int
END();
但是现在假设有人出现并向我们的模式添加了一种新的数据成员:字段对(x, xLength)。我们想像这样更改我们的便利宏...
#define START(obj) do { const auto& current = (obj)
#define OUTPUT(fieldname) \
printf("type of %s.%s is %s\n", #type, #fieldname, \
std::is_same<decltype(std::declval<current>().fieldname),int> ? "int" :
hasfield(current, fieldname##Length) ? "Pascal string" : "C string")
#define END() } while (0)
struct Baz { char *x, *y, *z; int xLength, zLength; };
START(Baz);
OUTPUT(x); // type of Baz.x is Pascal string
OUTPUT(y); // type of Baz.y is C string
OUTPUT(z); // type of Baz.z is Pascal string
END();
我自己设法想出了以下适用于 Clang 的 hasfield 实现......
#define hasfield(classtype, fieldname) \
[]() { \
struct X { \
template<class T, int=sizeof(&T::fieldname)> static constexpr bool f(T*){ return true; } \
static constexpr bool f(...) { return false; } \
}; return X::f((classtype*)0); \
}()
...但不幸的是,这似乎是由于a bug in Clang;根据 C++11 标准,本地类X 不允许有模板成员。事实上,这段代码无法用 GCC 编译。
所以我被难住了:在 C++11 中可能定义 OUTPUT 宏以便它做我想做的事吗?
绝对约束:不改变Baz的结构定义。无需提前对fieldname 进行硬编码。
Nice-to-haves:一个hasfield(c,f) 宏,也可以在其他上下文中使用(而不是将代码直接缠绕到OUTPUT 宏中)。不假设offsetof(c,fLength)==offsetof(c,f)+sizeof(std::declval<c>().f)。
【问题讨论】:
-
根本不是答案,只是提示:即使
m是非静态数据成员,您也可以将sizeof(std::declval<T>().m)简化为sizeof(T::m)(与decltype类似)。 -
我可以想象
typeid().name()和__cxa_demangle在序列化时会派上用场。只是一个提示
标签: c++ c++11 macros template-meta-programming