#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 stringEND();START(bar); OUTPUT(x); // type of bar.x is string OUTPUT(y); // type of bar.y is intEND();
但现在让我们说有人出现并为我们的架构添加了一种新的数据成员:字段对(x,xLength).我们想要像这样改变我们的便利宏……
#define START(obj) do { const auto& current = (obj)#define OUTPUT(fIEldname) \ printf("type of %s.%s is %s\n",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 stringEND();
就我自己而言,我设法提出了以下适用于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的结构定义.没有提前对字段名进行硬编码.
Nice-to-haves:一个hasfIEld(c,f)宏,也可以在其他上下文中使用(而不是将代码直接缠绕到OUTPUT宏中).假设offsetof(c,fLength)== offsetof(c,f)sizeof(std :: declval< c>().f).
解决方法 通过继承当前和依赖阴影,可以使用一些可能或可能不重要的限制:声明一个本地fIEldname变量,创建一个从你正在检查的类型派生的本地类,并在成员函数,检查fIEldname是否仍然引用局部变量.如果是,则不存在成员字段名.#include <utility>#include <stdio.h>#define START(type) do { typedef type current; const char typename[] = #type#define HASMEMBER(fIEldname) \ []() -> bool { \ struct HASMEMBER1 { } fIEldname; \ struct HASMEMBER2 : current { \ static char TEST1(HASMEMBER1&); \ static char (&TEST1(...))[2]; \ auto TEST2() -> decltype(TEST1(fIEldname)); \ }; \ return sizeof(std::declval<HASMEMBER2>().TEST2()) == 2; \ }()#define OUTPUT(fIEldname) \ printf("type of %s.%s is %s\n",typename,\ std::is_same<decltype(current::fIEldname),int>::value ? "int" : \ HASMEMBER(fIEldname##Length) ? "Pascal string" : "C string")#define END() } while (0)struct Foo { int i; char *j; char *k; };struct bar { char *x; int y; };struct Baz { char *x,zLength; };int main(){START(Foo); OUTPUT(i); // type of Foo.i is int OUTPUT(j); // type of Foo.j is C string OUTPUT(k); // type of Foo.k is C stringEND();START(bar); OUTPUT(x); // type of bar.x is C string OUTPUT(y); // type of bar.y is intEND();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 stringEND();}
编辑参加GCC 4.6.3.它仍然被GCC 4.8.1和clang 3.3接受,并且也应该与GCC 4.7.3一起使用(但不是4.7.2).
总结以上是内存溢出为你收集整理的是否有可能在C 11中写出(S,f)或hasfield(S,f)的宏存在?全部内容,希望文章能够帮你解决是否有可能在C 11中写出(S,f)或hasfield(S,f)的宏存在?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)