如何使用宏或元编程在C++中创建'passthru'函数?
所以我有一系列的全球性职能,说:如何使用宏或元编程在C++中创建'passthru'函数?
foo_f1(int a, int b, char *c);
foo_f2(int a);
foo_f3(char *a);
我想打一个C围绕这些++包装,一样的东西:
MyFoo::f1(int a, int b, char* c);
MyFoo::f2(int a);
MyFoo::f3(char* a);
有大约40起类似这样的,他们中的35我只想通过全局函数,其他5我想做一些不同的事情。
理想MyFoo.cpp的实施将是这样的:
PASSTHRU(f1, (int a, int b, char *c));
PASSTHRU(f2, (int a));
MyFoo::f3(char *a)
{
//do my own thing here
}
,但我有麻烦找出一种优雅的方式,使上述PASSTHRU宏。
我真正需要的是下面有点像神话X getArgs():
MyFoo::f1(int a, int b, char *c)
{
X args = getArgs();
args++; //skip past implicit this..
::f1(args); //pass args to global function
}
但短期下探到组装,我不能找到一个很好的实现getArgs的()的。
你可以使用Boost.Preprocessor让以下内容:
struct X {
PASSTHRU(foo, void, (int)(char))
};
...扩展为:
struct X {
void foo (int arg0 , char arg1) { return ::foo (arg0 , arg1); }
};
...使用这些宏:
#define DO_MAKE_ARGS(r, data, i, type) \
BOOST_PP_COMMA_IF(i) type arg##i
#define PASSTHRU(name, ret, args) \
ret name (\
BOOST_PP_SEQ_FOR_EACH_I(DO_MAKE_ARGS, _, args) \
) { \
return ::name (\
BOOST_PP_ENUM_PARAMS(BOOST_PP_SEQ_SIZE(args), arg) \
); \
}
该死的,打败我吧;也更优雅。你有一个错误虽然;)〜 – 2010-05-24 21:04:40
这导致无限递归。 :) – GManNickG 2010-05-24 21:13:11
@GMan:哎呀,谢谢。 – 2010-05-24 21:23:48
我最初的想法,这可能不起作用,或者其他人会说这个,是把所有的基础功能放在一个虚拟的类中。然后,将功能改进写入继承的类并与其一起运行。这不是一个宏包装,但你可以随时在虚拟类中调用全局函数。
随着一些组装技巧,你可能可以做到你想要的,但你会失去更多的可移植性。有趣的问题,我也想听到别人的答案。
如果您不想处理班级内容,例如this
,您可能需要使用namespace
。你也可以在课堂上使用static
成员方法,但我认为人们不再喜欢这种方法。
#ifndef __cplusplus
#define PASSTHRU(type, prefix, func, args) type prefix##_##func args
#else
#define PASSTHRU(type, prefix, func, args) type prefix::func args
#endif
或者
#ifndef __cplusplus
#define PASSTHRU(type, prefix, func, ...) type prefix##_##func(__VA_ARGS__)
...
语法稍有不同,但...
#include <boost/preprocessor.hpp>
#include <iostream>
void f1(int x, int y, char* z) { std::cout << "::f1(int,int,char*)\n"; }
#define GENERATE_ARG(z,n,unused) BOOST_PP_CAT(arg,n)
#define GET_ARGS(n) BOOST_PP_ENUM(n, GENERATE_ARG, ~)
#define GENERATE_PARAM(z,n,seq) BOOST_PP_SEQ_ELEM(n,seq) GENERATE_ARG(z,n,~)
#define GENERATE_PARAMS(seq) BOOST_PP_ENUM(BOOST_PP_SEQ_SIZE(seq), GENERATE_PARAM, seq)
#define PASSTHROUGH(Classname, Function, ArgTypeSeq) \
void Classname::Function(GENERATE_PARAMS(ArgTypeSeq)) \
{ \
::Function(GET_ARGS(BOOST_PP_SEQ_SIZE(ArgTypeSeq))); \
}
struct test
{
void f1(int,int,char*);
};
PASSTHROUGH(test,f1,(int)(int)(char*))
int main()
{
test().f1(5,5,0);
std::cin.get();
}
你可以得到的东西更接近你的,如果你使用的元组,但你必须提供ARG计数基本功能(你可以从元组中派生一个大小)。有点像这样:
PASSTHROUGH(test,f1,3,(int,int,char*))
那关于你在找什么?我知道这可以做到;花了大约半小时来解决。你似乎期望有一个隐含的“这个”必须被摆脱,但我不明白为什么......所以也许我误解了这个问题。无论如何,这可以让你快速创建默认的“passthrough”成员函数,这些成员函数遵循一些全局函数。如果您想跳过必须声明它们的所有内容,则需要DECPASSTHROUGH作为类声明...或者您可以修改它以创建内联函数。
提示:使用BOOST_PP_STRINGIZE((XX))来测试预处理器元函数的输出。
如果你直接访问内存,'这'将只是一个问题。 感谢您的解决方案,希望这里的人可以使用包括Boost预处理器(我们不使用Boost,但PP看起来是独立的)。 – Ryan 2010-05-24 21:24:46
好吧,如果那里的人对使用boost并不确定,那么你可以在每个其他C++开发者不能使用boost的时候做些什么:尝试写出你真正需要的那些部分,做得不好,并且感叹你的老板无能。 – 2010-05-24 21:40:21
@Ryan:PP是独立的,甚至可以在C中工作。或者,您可以随时使用[bcp](http://www.boost.org/tools/bcp/index.html)工具提取Boost组件。 – 2010-05-24 22:04:33
完美的转发依赖于右值引用。 STL在http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx上有一个博客条目,你会想选择一个支持该功能的编译器来采用这种方法。他正在讨论Visual C++ 2010.
OP实际上并不需要完美的转发,因为它们提供了足够的信息来转发正确的类型。当您在更通用的层面上工作时,需要完美的转发。给定任意一个在注释中解释的宏实现,OP可以将int&或int const&放到注释中,并且将按照指定的顺序转发给最终的实现函数。 – 2010-05-24 21:17:41
在40多个函数中,您可以在一个小时内手工输入包装。编译器将检查结果的正确性。假设每个需要包装的新功能需要2分钟,签名需要更改1分钟。
按照规定,没有提及频繁的更新或更改,听起来不像这个问题需要一个狡猾的解决方案。
所以,我的建议是保持简单:手工操作。将原型复制到源文件中,然后使用键盘宏(emacs/Visual Studio/vim)修复和/或多次搜索和替换,生成一组定义和一组声明。剪切声明,粘贴到标题中。填写非传递函数的定义。这不会赢得任何奖项,但它很快就会结束。
没有额外的依赖关系,没有新的构建工具,适用于代码浏览/标记/智能感知/等,适用于任何调试器,没有专门的语法/现代特征/模板等等,所以任何人都可以理解结果。 (的确,没有人会留下深刻的印象 - 但它会是一种不起眼的表现。)
大多数情况下,在当前版本的C++中这是不可能的。如果你的Google是“完美的转发”,你应该得到很多关于它为什么现在不能工作的点击,以及C++ 0x为帮助解决问题而添加的内容。 – 2010-05-24 19:46:41
使全局函数成为一个类的成员有什么作用,特别是当你试图跳过'this'呢? – GManNickG 2010-05-24 19:52:45