带reff限定符的重载解析
Overload resolution with ref-qualifiers
在使用refqualified函数重载时,我从GCC (4.8.1)和Clang(2.9和trunk)得到不同的结果。考虑下面的代码:
#include <iostream>
#include <utility>
struct foo
{
int& bar() &
{
std::cout << "non-const lvalue" << std::endl;
return _bar;
}
//~ int&& bar() &&
//~ {
//~ std::cout << "non-const rvalue" << std::endl;
//~ return std::move(_bar);
//~ }
int const& bar() const &
{
std::cout << "const lvalue" << std::endl;
return _bar;
}
int const&& bar() const &&
{
std::cout << "const rvalue" << std::endl;
return std::move(_bar);
}
int _bar;
};
int main(int argc, char** argv)
{
foo().bar();
}
Clang编译它并输出"const rvalue"
,而GCC认为这是一个模棱两可的调用,两个const限定函数都是最可行的候选者。如果我提供所有4个重载,那么两个编译器都输出"non-const rvalue"
。
我想知道哪个编译器——如果有的话——正在做正确的事情,以及相关的标准部分是什么。
注意:这实际上很重要的原因是实际代码将两个const限定函数声明为constexpr
。当然,没有输出到std::cout
,并且使用static_cast
代替std::move
,因此它们是有效的constexpr
定义。由于在 c++ 11中 constexpr
仍然意味着const
,因此不能提供在示例代码中注释掉的重载,因为它将重新定义const限定的右值重载。
首先,隐式object参数被视为13.3.1.4中的正常参数:
对于非静态成员函数,隐式对象形参的类型为- "对cv X的左值引用"对于没有引用限定符或带有&ref-qualifier
-使用&&声明的函数的"对cv X的右值引用"ref-qualifier
,其中X是函数所属的类,cv是成员的cv-限定条件函数声明。
所以你问的是等价于以下内容:
void bar(foo&);
void bar(foo&&);
void bar(const foo&);
void bar(const foo&&);
int main()
{
bar(foo());
}
表达式foo()
是一个类的右值。
其次,非const左值引用版本是不可行的,因为右值不能绑定到它。
这给我们留下了三个可行的重载解析函数。
每个都有一个隐式对象参数(const foo&
, foo&&
或const foo&&
),所以我们必须对这三个进行排序以确定最佳匹配。
三种可能的绑定(const foo&
, foo&&
和const foo&&
)的排序在13.3.3.2.3中描述:
标准转换序列S1优于标准转换序列S2,如果
- S1和S2都是引用绑定,它们都不指向未声明ref-qualifier的非静态成员函数的隐式对象形参[此处不适用此例外,它们都有ref-qualifier], S1将右值引用绑定到右值[类的prvalue是右值], S2绑定左值引用。
这意味着foo&&
和const foo&&
都比const foo&
好。
- S1和S2是引用绑定,除了顶级的cv限定符之外,引用所指向的类型是相同的,并且S2初始化的引用所指向的类型比S1初始化的引用所指向的类型更符合cv限定。
这意味着foo&&
比const foo&&
更好。
所以Clang是对的,这是GCC中的一个bug。foo().bar()
的过载排名如下:
struct foo
{
int&& bar() &&; // VIABLE - BEST (1)
int const&& bar() const &&; // VIABLE - (2)
int const& bar() const &; // VIABLE - WORST (3)
int& bar() &; // NOT VIABLE
int _bar;
};
GCC中的错误似乎纯粹适用于隐式对象参数(与ref-qualifiers
),对于正常参数,它似乎得到正确的排名,至少在4.7.2中。
- 继承函数的重载解析
- 你能重载对象变量名本身返回的内容吗
- 从父命名空间重载类型
- 使用C++中的模板和运算符重载执行矩阵运算
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 重载操作程序时出错>>用于类中的字符串 memebr
- 一个关于在C++中重载布尔运算符的问题
- 不同翻译单元中不可重载的非内联函数定义
- 为什么使用SFINAE而不是函数重载
- 为什么我不能在 C++ 中的特定函数重载中调用同一函数的任何其他重载?
- 将重载的成员函数传递给函数模板
- c++:可变模板和函数重载
- 重载元组索引运算符-C++
- 如何使用重载的相等(==)运算符向测试用例添加描述
- 重载==不适用于二进制树
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 重载运算符new[]的行为取决于析构函数
- 正在尝试重载二进制搜索树分配运算符
- 重载Singly Linked List中的赋值运算符
- 带reff限定符的重载解析