通过自由函数或成员函数扩展的机制
包含标准的大量C ++库允许您调整对象以便在库中使用。选择通常在成员函数或同一名称空间中的自由函数之间。
我想知道函数和构造库代码用于调用一个调用这个“扩展”函数之一的调用,我知道这个决定必须在编译期间进行,并涉及模板。以下运行时伪代码不可能/无意义,原因超出了本问题的范围。
if Class A has member function with signature FunctionSignature
choose &A.functionSignature(...)
else if NamespaceOfClassA has free function freeFunctionSignature
choose freeFunctionSignature(...)
else
throw "no valid extension function was provided"
上面的代码看起来像运行时代码:/。那么,库如何找出一个类所在的命名空间,它如何检测这三个条件,还有哪些需要避免的陷阱。
我的问题的动机是让我能够在库中找到调度块,并能够在我自己的代码中使用这些构造。所以,详细的答案将有所帮助。
!!赢得胜利!
好的,根据Steve(和评论)的答案,ADL和SFINAE是在编译时连接调度的关键结构。我的头部是ADL(原始)和SFINAE(再次是粗鲁的)。但我不知道他们是如何以我认为应该的方式共同组织的。
我想看一个如何将这两个结构组合在一起的说明性示例,以便库可以在编译时选择是在对象中调用用户提供的成员函数,还是在同一对象的命名空间中提供的用户提供的自由函数。这应该只使用上面的两个构造来完成,没有任何类型的运行时分派。
让我们说有问题的对象叫做NS::Car
,这个对象需要提供MoveForward(int units)
的行为,作为c的成员函数。如果要从对象的命名空间中拾取行为,它可能看起来像MoveForward(const Car & car_, int units)
。让我们定义想要发送的函数mover(NS::direction d, const NS::vehicle & v_)
,其中direction是枚举,v_是NS::car
的基类。
没有找到相关结果
已邀请:
5 个回复
缮记箔
这样用户可以提供自己的“the_operation”重载, 在与他的类相同的命名空间中,所以它是由ADL发现的。当然 用户的“the_operation”必须比默认“更专业” 实现 - 否则调用将是模糊的。 在实践中,这不是一个问题,因为一切限制 参数的类型多于它对任何东西的引用 “更专业”。 例:
编辑:在再次阅读Steve Jessop的回答之后,我意识到这基本上就是他写的,只有更多的话:)
厦惫
添加成员函数来改变
的行为,所以我不太清楚你的意思。
外镶受继
(2)是一个元函数,用于在给定的类
中检查具有签名
的该名称的成员函数的存在。
(3)使用此信息调用成员函数(如果存在)或者回退到调用自由函数(如果不存在)。
只需将
的调用委托给
(5)。 as-posted代码将调用
(1),但如果删除,重命名该成员函数或更改其签名,则将调用
。 另请注意,因为
是模板,所以必须进行SFINAE检查以保留仅允许从
派生的对象传入
(4)的语义。为了证明,如果一个注释(7)和注释(8),将使用类型为
(6)的对象调用
,尽管事实是
,我们仍然想要禁止它。 (注意:如果您的标准库没有
和
,请使用
或
变体。) 通常使用这种代码的方式是始终调用自由函数,并根据类似于
的方式实现自由函数,这样自由函数只调用传入对象的成员函数(如果存在),而不必编写重载对于可能具有适当成员函数的每种可能类型的自由函数。
bab
(2)当涉及多个对象时,自由(“全局”或“模块”)函数是优选的,并且对象不是彼此的部分/组合。或者,当函数使用普通数据时(没有方法的结构,基本类型)。
当某些常用模块函数访问对象时,在C ++中,您有“friend关键字”,允许它们访问对象方法,而不考虑范围。
在“几乎纯粹的面向对象”编程语言(如Java或C#)中,您不能使用自由函数,自由函数将被静态方法替换,这使得事情变得更加复杂。
讼乐
使用转发相同功能的基类:
如果从SomethingBase派生的某个类没有实现DoSomething()调用它将调用SomethingBase :: DoSomething() - > NS :: DoSomething():
如果派生自SomethingBase的另一个类B实现DoSomething()调用它将调用B :: DoSomething():
因此,在派生自SomethingBase的对象上调用DoSomething()将执行成员(如果存在),否则执行free函数。请注意,没有任何内容可以抛出,如果与您的调用不匹配,则会出现编译错误。