我想知道机制,并构建库代码用于调度一个调用其中一个“扩展”函数的函数,我知道这个决定必须在编译时发生并涉及模板.以下运行时版本的psuedocode是不可能/无意义的,原因超出了这个问题的范围.
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"
上面的代码看起来像运行时代码:/.那么,图书馆如何找出一个类所在的命名空间,它如何检测三个条件,还有什么其他的陷阱是需要避免的.
我的问题的动机是让我能够在库中找到调度块,并且能够使用我自己的代码中的结构.所以,详细的答案将有所帮助.
!!赢得BOUNTY!
好的,根据史蒂夫的回答(和意见),ADL和SFINAE是编译时接线调度的关键.我已经把我的头放在ADL(原始)和SFINAE(再次粗暴的).但我不知道他们如何按照我认为应该的方式在一起.
我想看到一个如何将这两个结构放在一起的说明性示例,以便库可以在编译时选择是否调用对象中的用户提供的成员函数,或者在同一对象的命名空间中提供的用户提供的免费函数.这只能使用上面的两个结构来完成,没有任何类型的运行时调度.
让我们说这个对象被称为NS :: Car,这个对象需要提供MoveForward(int unit)的行为,作为c的成员函数.如果从对象的命名空间中获取行为,它可能看起来像MoveForward(const Car& car_,int units).让我们定义要调度移动器(NS :: direction d,const NS :: vehicle& v_)的函数,其中direction是枚举,而v_是NS :: car的基类.
解决方法
Detecting the Existence of Member Functions at Compile-Time
但是,这不会让你想去,因为它只适用于静态类型.因为你想传递一个“参考到车”,所以没有办法测试动态类型(引用后面的具体对象的类型)是否具有这样一个成员函数.
如果你为静态类型定居,那么还有另外一种方式来做一个非常相似的事情.
它实现“如果用户提供重载的自由功能,调用它,否则尝试调用成员函数”.它就像这样:
namespace your_ns { template <class T> void your_function(T const& t) { the_operation(t); // unqualified call to free function } // in the same namespace,you provide the "default" // for the_operation as a template,and have it call the member function: template <class T> void the_operation(T const& t) { t.the_operation(); } } // namespace your_ns
这样用户可以提供自己的“the_operation”超载,
在与他的班级相同的命名空间中,所以它被ADL发现.当然
用户的“the_operation”必须比您的默认值更“专业化”
实现 – 否则调用将是不明确的.
实际上这不是一个问题,因为所有限制
参数的类型多于它作为对任何事件的引用到const
“更专业化”.
例:
namespace users_ns { class foo {}; void the_operation(foo const& f) { std::cout << "foo\n"; } template <class T> class bar {}; template <class T> void the_operation(bar<T> const& b) { std::cout << "bar\n"; } } // namespace users_ns
编辑:再次阅读史蒂夫·杰西普的回答后,我意识到这基本上是他写的,只有更多的话:)