通过自由函数或成员函数进行扩展的机制 [英] The mechanics of extension via free functions or member functions

查看:140
本文介绍了通过自由函数或成员函数进行扩展的机制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++库的加载(包括标准)允许您调整对象以在库中使用。选择通常在同一命名空间中的成员函数或自由函数之间。



我想知道机制和构造库代码用于调度一个调用,这将调用这些扩展函数之一,我知道这个决定必须地方在编译时间和涉及模板。以下运行时间伪代码不可能/无意义,原因超出了此问题的范围。

 如果A类具有带签名的成员函数FunctionSignature 
选择& A.functionSignature(...)
else如果NamespaceOfClassA有自由函数freeFunctionSignature
选择freeFunctionSignature(...)
else
throw没有提供有效的扩展函数

上面的代码看起来像运行时代码:/。那么,库如何找出一个类所在的命名空间,它如何检测三个条件,还有什么其他陷阱需要避免。



我的问题的动机是我能够在库中找到调度块,并能够使用我自己的代码中的构造。



> Ok所以根据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_是一个base

解决方案

你如何在编译时检测某个名字(和签名)的成员函数的存在。我的朋友在这里描述:



在编译时检测成员函数的存在



但是,这不会让你去哪里,因为它只适用于静态类型。因为你想传递一个引用到车辆,没有办法来测试动态类型(引用后面的具体对象的类型)是否有这样的成员函数。



如果你决定静态类型,还有另一种方法来做一个非常相似的事情。
它实现如果用户提供了一个重载的自由函数,调用它,否则尝试调用成员函数。它就像这样:

 命名空间your_ns {

template< class T&
void your_function(T const& t)
{
the_operation(t); //在同一命名空间中对自由函数
}

//进行无限制调用,为the_operation提供默认
//作为模板,并将其调用成员函数:

模板< class T>
void the_operation(T const& t)
{
t.the_operation();
}

} //命名空间your_ns

用户可以提供它自己的重载的the_operation,
在同一命名空间作为他的类,所以它是由ADL发现。当然
用户的the_operation必须比你的默认
实现更专业 - 否则调用将是不明确的。
在实践中,这不是一个问题,但是,限制
参数的类型,而不是一个引用到const到任何东西将是
更专业化。



示例:

  namespace users_ns {

class foo {};

void the_operation(foo const& f)
{
std :: cout< foo\\\
;
}

template< class T>
class bar {};

template< class T>
void the_operation(bar< T> const& b)
{
std :: cout< 谷仓;
}

} //命名空间users_ns

阅读Steve Jessop的回答,我意识到这基本上是他写的,只有更多的话:)


Loads of C++ libraries, the standard included, allow you to adapt your objects for use in the libraries. The choice is often between a member function or a free function in the same namespace.

I'd like to know mechanics and constructs the library code uses to dispatch a call which will call one of these "extension" functions, I know this decision has to take place during compile time and involves templates. The following runtime psuedocode is not possible/non-sense, the reasons are out of the scope of this question.

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"

The code above looks like runtime code :/. So, how does the library figure out the namespace a class is in, how does it detect the three conditions, what other pitfalls are there that need to be avoided.

The motivation for my question is for me to be able to find the dispatch blocks in libraries, and to be able to use the constructs in my own code. So, detailed answers will help.

!!TO WIN BOUNTY!!

Ok so according to the answer from Steve (and the comments) ADL and SFINAE are the key constructs for wiring up the dispatch at compile time. I've got my head arround ADL (primitively) and SFINAE (again rudementary). But I don't know how they orchistrate together in the way I think they should.

I want to see a illustrative example of how these two constructs can be put together so that a library can choose at compile time whether to call a user supplied member function in an object, or a user supplied free function supplied in the same object's namespace. This should only be done using the two constructs above, no runtime dispatch of any sort.

Lets say the object in question is called NS::Car, and this object needs to provide the behaviour of MoveForward(int units), as a member function ofc. If the behaviour is to be picked up from the object's namespace it will probably look like MoveForward(const Car & car_, int units). Lets define the function that wants to dispatch mover(NS::direction d, const NS::vehicle & v_) , where direction is an enum, and v_ is a base class of NS::car.

解决方案

Well, I can tell you how to detect the presence of member functions of a certain name (and signature) at compile time. A friend of mine describes it here:

Detecting the Existence of Member Functions at Compile-Time

However that won't get you where you want to go, because it only works for the static type. Since you want to pass a "reference-to-vehicle", there is no way to test if the the dynamic type (the type of the concrete object behind the reference) has such a member function.

If you settle for the static type though, there is another way to do a very similar thing. It implements "if the user provides an overloaded free function, call it, otherwise try to call the member function". And it goes like this:

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

That way the user can provide it's own overload of "the_operation", in the same namespace as his class, so it's found by ADL. Of course the user's "the_operation" must be "more specialized" than your default implementation - otherwise the call would be ambiguous. In practice that's not a problem though, since everything that restricts the type of the parameter more than it being a reference-to-const to anything will be "more specialized".

Example:

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

EDIT: after reading Steve Jessop's answer again, I realize that's basically what he wrote, only with more words :)

这篇关于通过自由函数或成员函数进行扩展的机制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆