C ++ 11:抽象const,volatile,左值引用和rvalue引用限定成员函数指针?

时间:2012-01-15 19:16:48

标签: c++ c++11 overloading member-function-pointers qualifiers

C ++ 03允许您将函数参数限定为constvolatile和/或左值引用(&)。

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 ^ 4-4中有2 ^ 2 = 4种可能性在C ++ 11中= 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说:

  

错误:形成指向引用类型'Baz&amp;&amp;'

的指针

但这并不太令人惊讶,因为截至4.7的GCC尚未支持this上的参考资格。

我也尝试过使用Clang 3.0,它确实有这样的支持:

  

错误:成员指针指的是非类型'Baz&amp;&amp;'

哦,好吧。

我是否正确得出结论认为这是不可能的,并且没有办法在成员函数指针的“this type”上抽象引用限定符?当您将“this类型”作为模板参数传递时,除了特定情况之外的任何其他抽象符合条件的技术(特别是在this上)也将受到赞赏。

(值得指出的是,如果C ++没有区分成员函数和普通函数,这将是微不足道的:你将模板参数用作函数(指针)的参数类型,并且模板参数将按原样传递,限定符完整,无需额外考虑。)

1 个答案:

答案 0 :(得分: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次。