C++11:对const、volatile、左值引用和右值引用限定的成员函数指针进行抽象
C++11: Abstracting over const, volatile, lvalue reference, and rvalue reference qualified member function pointers?
C++03允许您将函数参数限定为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中,const
和volatile
限定符是可能的,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个重载。每个函数。
我很高兴地发现,如果您将封闭类的类型作为模板参数传递,并从中派生成员函数指针的类型,那么const
和volatile
限定符是允许的,并按您所期望的那样传播:
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&;'
但这并不太令人惊讶,因为GCC从4.7开始还不支持this
上的参考限定符。
我也在Clang 3.0上尝试过,它确实有这样的支持:
错误:成员指针指向非类类型"Baz&;'
哦,好吧。
我得出的结论是正确的吗?这是不可能的,并且没有办法在成员函数指针的"this type
"上抽象过引用限定符?除了将"this
类型"作为模板参数传递的特定情况之外,任何其他用于对限定符进行抽象的技术(尤其是在this
上)也将受到赞赏。
(值得指出的是,如果C++不区分成员函数和普通函数,这一切都将是微不足道的:您将使用模板参数作为函数(指针)的参数类型,模板参数将按原样传递,限定符完好无损,无需额外考虑。)
您有没有想过简单地专门化您的模板?
你可以添加两个版本:
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次代码。
- 具有引用成员的结构是否具有唯一的对象表示形式
- 初始化右值引用成员
- C++通过绑定到引用成员而缩短临时变量寿命?
- C++为具有引用成员变量的类创建复制构造函数
- 常量和引用成员函数限定符
- C++将引用成员绑定到构造函数参数
- 如果包含引用成员的类中缺少原始变量,为什么它仍然可以访问?
- 初始化指针或引用成员变量以指向另一个成员
- 将常量引用成员设置为临时变量是否安全
- 对象超出范围后,引用成员设置为 0
- 复制构造函数初始化初始化列表中的引用成员会导致指针悬空
- 使用默认构造函数引用成员变量初始化错误
- 如何从派生类访问引用成员变量?
- Visual Studio 2017 允许在构造函数中使用自身初始化引用成员.真的是合法的C++吗?
- 为什么当类具有引用成员时C++编译器不删除复制构造函数
- 引用成员到构造函数参数按值传递
- 在执行不平凡的构造函数之前引用成员
- 具有引用成员变量的多态性
- 从按值构造函数参数初始化的引用成员
- 深度复制包含引用成员(C++)的结构