2012-01-15 118 views
13

C++ 03允许您将函数参数限定为const,volatile和/或左值引用(&)。C++ 11:抽象const,volatile,左值引用和右值引用合格的成员函数指针?

C++ 11增加了一个:右值引用(&&)。此外,C++允许您基于参数的限定符重载函数,以便在调用函数时选择最合适的重载。

成员函数在概念上可以被认为是一个函数,它接受一个额外的参数,其类型是对其所属类的实例的引用。基于这个“额外参数”限定符的成员函数可以像其他任何参数一样重载。这是通过把在限定符函数签名的端部表示为:

struct Foo 
{ 
    int& data();    // return a non-const reference if `this` is non-const 
    const int& data() const; // return a const reference if `this` is const 
}; 

在C++ 03,constvolatile限定符是可能的,以及C++ 11还允许&&&&理论上可以有被允许在C++ 03中,但它不是)。

可以使用限定符的任意组合,但&&&是互斥的,这使C++ 03中的2^2 = 4个可能性和C++ 11中的2^4-4 = 12 。

这可以是一个相当痛苦,当你想使用成员函数指针的工作,因为他们甚至没有一点点的多态性在这些限定:在成员函数指针的“this类型”为顺利通过了预选赛参数必须与它传递的参数类型完全匹配。 C++也没有提供明确的工具来抽象限定符。在C++ 03中,这大多是好的,因为你必须编写const版本和非const版本,没有人关心volatile,但是在C++ 11的病态情况下(这并不罕见)是病态的),您可能必须手动编写多达12个重载。每个功能。

我很高兴地发现,如果你是通过封装类作为模板参数的类型,并能从中得到一个成员函数指针的类型,constvolatile预选赛被允许和传播你所期望的:

template<typename Object> 
struct Bar 
{ 
    typedef int (Object::*Sig)(int); 
}; 

Bar<Baz>;    // Sig will be `int (Baz::*)(int)` 
Bar<const Baz>;   // Sig will be `int (Baz::*)(int) const` 
Bar<volatile Baz>;  // Sig will be `int (Baz::*)(int) volatile` 
Bar<const volatile Baz>; // Sig will be `int (Baz::*)(int) const volatile` 

这是一个很大的不必手动写出所有的情况更好。

不幸的是,它似乎不适用于&&&

GCC 4.7说:

error: forming pointer to reference type ‘Baz&&’

但是,这不是太奇怪,因为作为GCC 4.7还没有对this参考预选赛支持。

error: member pointer refers into non-class type 'Baz &&'

呵呵,好了:

我也铛3.0,它确实有这样的支持试了一下。

我正确地断定这是不可能的,并且没有办法在成员函数指针的“this type”上抽象引用限定符吗?除了在通过“this类型”作为模板参数时的特定情况之外,还可以使用任何其他用于限定符(尤其是this)抽象的技术。 (值得指出的是,如果C++没有区分成员函数和普通函数,这将会很简单:您将使用模板参数作为函数(指针)的参数类型,并且模板参数将按原样传递,修饰符完好无损,无需额外考虑。)

+1

对于所有可能的限定符组合,你需要多少次不同的行为? (或者,对于这个问题,甚至有两种或三种可能的组合) – 2012-01-15 19:49:16

+1

如果我想为函数类对象编写一个抽象(本质上是std :: function但不一样),那么完整性是一个设计目标。我无法真正推断或估计(至于多频繁),但我知道我以前遇到过它。 – glaebhoerl 2012-01-15 20:25:29

回答

4

您是否想过简单地专门化您的模板?

您可以再补充两个版本:

template <typename Object> 
struct Bar<Object&> { 
    typedef int (Object::*Sig)(int)&; 
}; 

template <typename Object> 
struct Bar<Object&&> { 
    typedef int (Object::*Sig)(int)&&; 
}; 

然后编译器会适当地挑选合适的专业化(或退回到一般情况下)。

这可以节省您从const/volatile的事情,但确实意味着您需要编写代码3次。

+0

是的,'const'和'volatile'智能处理的事实意味着我只需要编写三个版本而不是十二个,这很好。 – glaebhoerl 2012-01-15 20:23:02