使用预处理器从f(列表)中删除参数列表

时间:2011-01-05 20:19:04

标签: c++ c-preprocessor

在我看来,我在升级库中看到了一些奇怪的事情,它最终正是我现在正在尝试做的事情。虽然找不到......

我想创建一个采用签名并将其转换为函数指针的宏:

void f(int,int) {}

...
void (*x)(int,int) = WHAT( (f(int,int)) );

x(2,4); // calls f()

我特别需要这个来处理成员函数指针,以便WHAT需要两个参数:

WHAT(ClassType, (f(int,int)); // results in static_cast<void (ClassType::*)(int,int)>(&ClassType::f)

为了解决我的问题,这不是绝对必要的,但它会让事情变得更好。


这个问题本身与函数指针没什么关系。需要做的是使用预处理器获取“f(int,int)”并将其转换为两个不同的部分:

'F' '(INT,INT)'


为什么:

我已经解决了这里提出的问题:Generating Qt Q_OBJECT classes pragmatically

我已经开始了一系列文章解释如何做到这一点: http://crazyeddiecpp.blogspot.com/2011/01/quest-for-sane-signals-in-qt-step-1.html http://crazyeddiecpp.blogspot.com/2011/01/quest-for-sane-signals-in-qt-step-2.html

签名必须从用户尝试连接的“信号”进行评估,并准确匹配。 Qt用户习惯将其表示为SIGNAL(fun(param,param)),因此connect_static(SIGINFO(object,fun(param,param)), [](int,int){})之类的内容不会太奇怪。

为了构造签名,我需要能够将其从提供的参数中拉出来。有足够的信息来获取成员函数地址(使用C ++ 0x的decltype)并获取签名以生成适当的包装器,但我看不出如何将其取出。我能提出的最接近的是SIGINFO(object, fun, (param,param)),这可能已经足够好了,但我想在考虑不可能得到我更喜欢的确切语法之前我会问这里。

1 个答案:

答案 0 :(得分:1)

不幸的是,使用标准预处理器你想做什么是不可能的。有几个原因:

  • 使用自定义字符拆分传递给宏的参数是不可能的。它们必须以逗号分隔。否则,这可以立即解决您的问题。
  • 您不能使用预处理器来定义不是标识符的内容。否则,您可以在()被定义为,的情况下使用双扩展,并在其上拆分参数,就像它作为f, int, int,传递一样,然后将其作为可变参数处理。
  • 不幸的是,C ++中的函数指针定义不允许您推导出给定义类型的名称。

更进一步,即使你设法创建一个函数指针,代码也不适用于方法,因为为了调用一个方法,你需要有两个指针 - 指向方法和类实例的指针。这意味着你必须有一些包装这个东西。

这就是为什么QT使用自己的工具如moc来生成粘合代码。

您可能在Boost中看到的关闭事物可能是Signals,Bind和Lambda库。具有讽刺意味的是,这些库比你想要实现的功能强大得多,但与此同时它们也不会让你以你想要的方式实现它。例如,即使您可以使用所需的语法执行所需的操作,如果信号具有不同的签名,您也无法将插槽“连接”到“信号”。与此同时,上面提到的Boost I的图书馆完全允许这样做。例如,如果“slot”需要的参数多于“signal”所提供的参数,则可以在调用“slot”时绑定要传递的其他对象。如果“slot”不期望它们,那些库也可以抑制额外的参数。

我认为从C ++前瞻性的最佳方式就是使用Boost Signal方法在GUI库中实现事件处理。 QT不会出于多种原因使用它。首先,当C ++不那么花哨的时候,就像90秒开始一样。此外,他们必须解析您的代码,以便在平面设计师中使用“插槽”和“信号”。

对我来说,而不是使用宏,甚至更糟糕的是 - 在C ++之上使用非标准工具生成代码,并使用以下内容:

void (*x)(int,int) = WHAT( (f(int,int)) );

做这样的事情要好得多:

void f (int x, int y, int z);
boost::function<void (int, int)> x = boost::bind (&f, _1, _2, 3);
x (1, 2);

以上将适用于各种功能和方法。