首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++11:抽象在const、易失性、lvalue引用和rvalue引用限定的成员函数指针上?

C++11:抽象在const、易失性、lvalue引用和rvalue引用限定的成员函数指针上?
EN

Stack Overflow用户
提问于 2012-01-15 19:16:47
回答 1查看 1.6K关注 0票数 13

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

C++11再添加一个: rvalue引用(&&)。

此外,C++允许根据参数的限定符重载函数,以便在调用函数时选择最合适的重载。

成员函数在概念上可以看作是一个函数,它接受一个额外的参数,其类型是对其所属类的实例的引用。基于这个“额外参数”的限定符,可以以与任何其他参数相同的方式重载成员函数。这可以通过将限定符放在函数签名的末尾来表示:

代码语言:javascript
复制
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中是允许的,但它不是)。

可以使用任何限定符的组合,但&&&是相互排斥的,这使得2^2 =4在C++03中的可能性和2^4-4 = 12在C++11中成为可能。

当您想使用成员函数指针时,这可能会很痛苦,因为它们在这些限定符中甚至一点都不是多态的:作为参数传递的成员函数指针的"this类型“上的限定符必须与传递给它的参数类型上的限定符完全匹配。C++也没有提供任何明显的工具来对限定符进行抽象。在C++03中,这基本上是可以的,因为您必须编写一个const版本和一个非const版本,而且没有人关心volatile,但是在C++11的病理案例中(这种情况并不像病理一样罕见),您可能需要手动编写多达12个重载。每种功能。

我很高兴地发现,如果您将封装类的类型作为模板参数传递,并从中派生成员函数指针的类型,那么constvolatile限定符将如您所期望的那样被允许和传播:

代码语言:javascript
复制
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++没有区分成员函数和正常函数,这一切都是微不足道的:您将使用模板参数作为函数(指针)的参数类型,模板参数将以原样传递,限定符完好无损,无需额外考虑。)

EN

回答 1

Stack Overflow用户

发布于 2012-01-15 20:03:33

你考虑过简单地专门化你的模板吗?

您只需添加以下两个版本:

代码语言:javascript
复制
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次代码。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8872550

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档