2010-05-24 26 views
7

所以我有一系列的全球性职能,说:如何使用宏或元编程在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的()的。

+1

大多数情况下,在当前版本的C++中这是不可能的。如果你的Google是“完美的转发”,你应该得到很多关于它为什么现在不能工作的点击,以及C++ 0x为帮助解决问题而添加的内容。 – 2010-05-24 19:46:41

+3

使全局函数成为一个类的成员有什么作用,特别是当你试图跳过'this'呢? – GManNickG 2010-05-24 19:52:45

回答

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) \ 
    ); \ 
    } 
+0

该死的,打败我吧;也更优雅。你有一个错误虽然;)〜 – 2010-05-24 21:04:40

+0

这导致无限递归。 :) – GManNickG 2010-05-24 21:13:11

+0

@GMan:哎呀,谢谢。 – 2010-05-24 21:23:48

0

我最初的想法,这可能不起作用,或者其他人会说这个,是把所有的基础功能放在一个虚拟的类中。然后,将功能改进写入继承的类并与其一起运行。这不是一个宏包装,但你可以随时在虚拟类中调用全局函数。

随着一些组装技巧,你可能可以做到你想要的,但你会失去更多的可移植性。有趣的问题,我也想听到别人的答案。

0

如果您不想处理班级内容,例如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__) 
... 
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))来测试预处理器元函数的输出。

+0

如果你直接访问内存,'这'将只是一个问题。 感谢您的解决方案,希望这里的人可以使用包括Boost预处理器(我们不使用Boost,但PP看起来是独立的)。 – Ryan 2010-05-24 21:24:46

+3

好吧,如果那里的人对使用boost并不确定,那么你可以在每个其他C++开发者不能使用boost的时候做些什么:尝试写出你真正需要的那些部分,做得不好,并且感叹你的老板无能。 – 2010-05-24 21:40:21

+0

@Ryan:PP是独立的,甚至可以在C中工作。或者,您可以随时使用[bcp](http://www.boost.org/tools/bcp/index.html)工具提取Boost组件。 – 2010-05-24 22:04:33

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.

+0

OP实际上并不需要完美的转发,因为它们提供了足够的信息来转发正确的类型。当您在更通用的层面上工作时,需要完美的转发。给定任意一个在注释中解释的宏实现,OP可以将int&或int const&放到注释中,并且将按照指定的顺序转发给最终的实现函数。 – 2010-05-24 21:17:41

5

在40多个函数中,您可以在一个小时内手工输入包装。编译器将检查结果的正确性。假设每个需要包装的新功能需要2分钟,签名需要更改1分钟。

按照规定,没有提及频繁的更新或更改,听起来不像这个问题需要一个狡猾的解决方案。

所以,我的建议是保持简单:手工操作。将原型复制到源文件中,然后使用键盘宏(emacs/Visual Studio/vim)修复和/或多次搜索和替换,生成一组定义和一组声明。剪切声明,粘贴到标题中。填写非传递函数的定义。这不会赢得任何奖项,但它很快就会结束。

没有额外的依赖关系,没有新的构建工具,适用于代码浏览/标记/智能感知/等,适用于任何调试器,没有专门的语法/现代特征/模板等等,所以任何人都可以理解结果。 (的确,没有人会留下深刻的印象 - 但它会是一种不起眼的表现。)

相关问题