我在这里发布了实施和简短的测试/演示: http://ideone.com/CNJDi
我提出了一种C ++代理方法,这种方法与我见过的其他东西不同。我想要解决的具体问题是有一个统一的函数指针解决方案,其中给定的实例可以是a)成员fn ptr + object ptr或b)nonmember fn ptr。初始化委托并将其交给其他代码后,他可以动态调用它,甚至不知道它来自哪种类型的对象(通常只能通过静态引用它来自的类来调用成员函数指针。 !)。从理论上说这很容易实现,但是C ++使得这样的事情变得更加困难。所以我扭曲了语言以使其发挥作用。
我实现的主要缺点是,由于成员函数指针的无效强制转换/调用,它在技术上并不符合“标准”(至少,我95%肯定标准不会在这里保护我......) 。但它确实碰巧在我测试它的编译器上工作(包括Visual Studio 2012)。我还认为很明显,如果编译器以简单的方式实现成员函数,它将“倾向于工作”。
我看了一些其他的实现,但对我来说,他们看起来似乎很复杂,使用起来很笨拙。有些人甚至依靠构建工具来生成存根函数来调用成员函数,而我只依赖于宏和模板。我认为缺乏合适的代表是C ++的一个主要缺点,但我发现我更讨厌这种解决方法。现在我需要决定我是否真的想要使用它,或者我只是喜欢它,因为我想到了它。
以下是您使用它的方式:
一个。声明委托类型
typedef DELEGATE(float, ARGS(int, int)) Delegate1;
此宏自动声明静态和成员函数指针类型,因此您不必两次键入签名。它扩展到Delegate<float (*)(int, int), float (Null::*)(int, int)>
。编译器使用其中任何一个是合适的,具体取决于委托实例的初始化方式以便稍后执行调用。编译器使用它来静态验证编码器调用提供的参数。 ARGS宏是与返回类型分离的纯语法糖:DELEGATE(float,int,int)是相同的。
B中。初始化:
Delegate1 d = Delegate1(test1); // static function
Delegate1 e = Delegate1((Delegate1::MemberType)&TestClass::test2, &obj); // member
这些静态和成员函数现在存储为相同的类型! obj必须是一个指向TestClass实例的有效指针,而TestClass :: test2最好返回一个float并将(int,int)作为参数,如上所述。这是主要的使用陷阱,编译器无法捕捉到这里所犯的错误。
℃。调用:INVOKE(d, ARGS(5, 6))
(在此示例中返回一个浮点数)
尽管它的外观,这个参数列表实际上与任何C ++函数调用一样安全!它使用上面提供的上述float(*)(int,int)签名验证参数!它可以支持任意数量的参数,只需匹配签名即可。如果添加太多/太少的参数,使用编译器中的错误参数类型等,则会出现友好的编译器错误。同样,ARGS是语法糖,INVOKE(d, 5, 6)
是相同的。
但是如果在不批准的编译器中使用INVOKE,它可能会使程序崩溃:(
我有几个问题:
答案 0 :(得分:2)
为什么不在C ++ 11 / Boost中使用std :: bind?可以使用成员函数,函数指针,lambda函数,仿函数和任何其他可调用对象。我个人更愿意不惜一切代价避免使用预处理器和宏;它可以使调试成为一个巨大的混乱。 Scott Meyers(Effective C ++,More Effective C ++和Effective STL的作者)也不鼓励使用预处理器。
bind的参考:http://en.cppreference.com/w/cpp/utility/functional/bind
我还考虑使用std :: function来封装各种类型,但是bind可以干净地处理几乎所有的东西。 http://en.cppreference.com/w/cpp/utility/functional/function
答案 1 :(得分:0)
任何人都可以找到我发布的实施示例无法正常运行的好编译器吗?
在我看来,如果代码首先不符合标准,那就无关紧要了。如果你必须以一种奇怪的方式查看语言规则,那么你的代码可能不符合标准。
符合标准的代码很重要,因为虽然编译器的实现细节可能会发生变化,但生成的二进制文件的观察行为却不能。作为标准合规性问题的错误比不符合标准的代码无效的错误更容易得到修复。
我希望这可以完全运行,或者编译器/程序在第一次使用时翻转。但是它有可能在一段时间内工作然后随机崩溃吗?
如果您的代码调用未定义的行为,那么让它工作得很好,然后在最糟糕的时候发生灾难性失败是标准允许的。
您认为这看起来容易/干净吗?或者你发现其他实现更简单?哪个?你能想到一个好方法吗? 以某种方式提高我的语法/可用性?
老实说,我认为这是一团糟。要使用你的代表,我必须使用三个不同的宏,一个显然不是可选的单独的typedef和一个C风格的强制转换。坦率地说,使用和观察是痛苦的。
你会用它吗?或者我应该咬紧牙关并使用一个 更安全但更复杂的替代解决方案?
老实说,如果您没有可用的C ++ 11编译器,我会使用std::function
和朋友(或boost::function
)。即使你发现std::function
更复杂,它肯定更清洁,更标准,更有能力。