所以我有一系列全局函数,比如说:
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()的良好实现。
答案 0 :(得分:10)
您可以使用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) \
); \
}
答案 1 :(得分:5)
在40多个功能中,您可以在一小时内手动输入包装纸。编译器将检查结果的正确性。假设需要换行的每个新功能额外需要2分钟,签名更改需要额外1分钟。
根据规定,并且没有提及频繁的更新或更改,听起来这个问题并不需要狡猾的解决方案。
所以,我的建议是保持简单:手工完成。将原型复制到源文件中,然后使用键盘宏(emacs / Visual Studio / vim)进行修复,和/或多次搜索和替换,生成一组定义和一组声明。剪切声明,粘贴到标题中。填写非传递函数的定义。这不会赢得任何奖项,但它很快就会结束。
没有额外的依赖,没有新的构建工具,适用于代码浏览/标签/ intellisense /等,适用于任何调试器,没有专门的语法/现代功能/模板/等,所以任何人都可以理解结果。 (确实没有人会留下深刻的印象 - 但这将是一种不受欢迎的好事。)
答案 2 :(得分:2)
语法略有不同但......
#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))测试预处理器元函数的输出。
答案 3 :(得分:0)
我最初的想法,这可能不起作用或其他人会说明这一点,就是将所有基本功能放在一个类中作为虚拟。然后,将功能改进写入继承的类并使用它运行。它不是宏包装器,但您总是可以在虚拟类中调用全局函数。
有了一些装配技巧,你可能会完全按照自己的意愿行事,但是你可能会失去可移植性。有趣的问题,我也希望听到其他人的答案。
答案 4 :(得分:0)
如果您不想处理课程内容,可能需要使用namespace
,例如this
。你也可以在课堂上使用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__)
...
答案 5 :(得分:0)
完美转发依赖于右值引用。 STL在http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx上有一个博客条目,您可能希望选择支持该功能的编译器来采用这种方法。他正在讨论Visual C ++ 2010。