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

发布于 2024-10-10 05:43:12 字数 1514 浏览 2 评论 0原文

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

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

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)'


为什么:

我已经解决了这里提出的问题: 实用地生成 Qt Q_OBJECT 类

我已经开始撰写一系列文章来解释如何做到这一点: 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)) ,这可能已经足够好了,但我想在考虑不可能获得确切的语法之前我应该​​先在这里问一下我更愿意。

It seems to me that I saw something weird being done in a boost library and it ended up being exactly what I'm trying to do now. Can't find it though...

I want to create a macro that takes a signature and turns it into a function pointer:

void f(int,int) {}

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

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

I especially need this to work with member function pointers so that WHAT takes two params:

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

It's not absolutely necessary in order to solve my problem, but it would make things a touch nicer.


This question has nothing, per-se, to do with function pointers. What needs to be done is to use the preprocessor to take "f(int,int)" and turn it into two different parts:

'f'
'(int,int)'


Why:

I've solved the problem brought up here: Generating Qt Q_OBJECT classes pragmatically

I've started a series of articles explaining how to do it:
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

The signature must be evaluated from, and match exactly, the "signal" that the user is attempting to connect with. Qt users are used to expressing this as SIGNAL(fun(param,param)), so something like connect_static(SIGINFO(object,fun(param,param)), [](int,int){}) wouldn't feel too strange.

In order to construct the signature I need to be able to pull it out of the arguments supplied. There's enough information to get the member function address (using C++0x's decltype) and fetch the signature in order to generate the appropriate wrapper but I can't see how to get it out. The closest I can come up with is SIGINFO(object, fun, (param,param)), which is probably good enough but I figured I'd ask here before considering it impossible to get the exact syntax I'd prefer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦旅人picnic 2024-10-17 05:43:12

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

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

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

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

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

我想说,从 C++ 的角度来看,目前最好的方法是使用 Boost Signal 方法在 GUI 库中实现事件处理。 QT 出于多种原因不使用它。首先,它始于 90 年代,当时 C++ 还没有那么奇特。另外,他们必须解析您的代码才能在图形设计器中使用“槽”和“信号”。

在我看来,不是使用宏,甚至更糟糕——在 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);

上面对函数和方法都适用。

What are you trying to do is impossible using standard preprocessor, unfortunately. There are a couple of reasons:

  • It is impossible to split parameters passed to a macro using custom character. They have to be comma delimited. Otherwise that could solve your problem instantly.
  • You cannot use preprocessor to define something that is not an identifier. Otherwise you could use double expansion where ( and ) is defined as , and split arguments on that as if it was passed as f, int, int,, then process it as variadic arguments.
  • Function pointer definition in C++ does not allow you to deduce the name given to defined type, unfortunately.

Going even further, even if you manage to create a function pointer, the code won't work for methods because in order to invoke a method, you need to have two pointers - pointer to the method and to the class instance. This means you have to have some wrapper around this stuff.

That is why QT is using its own tools like moc to generate glue code.

The closes thing you might have seen in Boost is probably Signals, Bind and Lambda libraries. It is ironic that those libraries are much more powerful than what you are trying to achieve, but at the same time they won’t allow you to achieve it the way you want it. For example, even if you could do what you want with the syntax you want, you won’t be able to “connect” a slot to a “signal” if signal has a different signature. At the same time, libraries from Boost I mentioned above totally allow that. For example, if your “slot” expects more parameters than “signal” provides, you can bind other objects to be passed when “slot” is invoked. Those libraries can also suppress extra parameters if “slot” does not expect them.

I’d say the best way from C++ prospective as for today is to use Boost Signal approach to implement event handling in GUI libraries. QT doesn’t use it for a number of reasons. First, it started in like 90-s when C++ was not that fancy. Plus, they have to parse your code in order to work with “slots” and “signals” in graphic designer.

It seems for me than instead of using macros or even worse – non-standard tools on top of C++ to generate code, and using the following:

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

It would be much better to do something like this:

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

Above will work for both functions and methods.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文