繁体   English   中英

如何使用宏或元编程在 C++ 中创建“passthru”函数?

[英]How can one make a 'passthru' function in C++ using macros or metaprogramming?

所以我有一系列全局函数,比如:

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

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

正如指定的那样,并且没有提到频繁的更新或更改,听起来这个问题并不需要一个狡猾的解决方案。

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

没有额外的依赖项,没有新的构建工具,可以很好地与代码浏览/标签/智能感知/等一起使用,可以很好地与任何调试器一起使用,并且没有专门的语法/现代功能/模板/等,因此任何人都可以理解结果。 (确实没有人会留下深刻的印象——但这将是一种不为所动的好。)

语法略有不同,但...

#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*))

那是关于你在寻找什么? 我知道这是可以做到的; 花了大约半个小时来解决。 您似乎期望必须摆脱一个隐含的“this”,但我不明白为什么......所以也许我误解了这个问题。 无论如何,这将让您快速创建默认的“直通”成员函数,这些函数遵循某些全局函数。 如果您想跳过必须全部声明它们,您将需要一个 DECPASSTHROUGH 类声明......或者您可以修改它以创建内联函数。

提示:使用 BOOST_PP_STRINGIZE((XX)) 来测试预处理器元函数的输出。

我最初的想法,这可能行不通,或者其他人会这样说,是将所有基本函数放在一个类中作为虚拟。 然后,将功能改进写入继承的类并使用它运行。 它不是宏包装器,但您始终可以在虚拟类中调用全局函数。

使用一些组装技巧,您可能完全可以做您想要的,但您很可能会失去可移植性。 有趣的问题,我也想听听其他人的答案。

如果你不想处理类的东西,你可能想要使用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__)
...

完美转发依赖于右值引用。 STL 在Link上有一个博客条目,您可能希望选择支持该功能的编译器来采用这种方法。 他正在讨论 Visual C++ 2010。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM