K-b*_*llo 20 c++ overloading language-lawyer c++11 ref-qualifier
While working with ref-qualified function overloads, I'm getting different results from GCC (4.8.1) and Clang (2.9 and trunk). Consider the following code:
#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();
}
Run Code Online (Sandbox Code Playgroud)
Clang compiles it and outputs "const rvalue", while GCC thinks this is an ambiguous call with the two const-qualified functions both being best viable candidates. If I provide all 4 overloads, then both compilers output "non-const rvalue".
I would like to know which compiler --if any-- is doing the right thing, and what are the relevant standard pieces in play.
注意:这实际上很重要的原因是真实代码将const限定的函数声明为constexpr.当然,没有输出std::cout和static_cast替代std::move,因此它们是有效的constexpr定义.并且因为在 C++ 11中 constexpr仍然暗示const,不能提供示例代码中注释掉的重载,因为它将重新定义const限定的rvalue重载.
And*_*zos 28
首先,根据13.3.1.4将隐式对象参数视为普通参数:
对于非静态成员函数,隐式对象参数的类型是
- 对于没有引用限定符或使用&ref-qualifier声明的函数的"对cv X的左值引用"
- 对于用&& ref-qualifier声明的函数的"对cv X的rvalue引用"
其中X是函数所属的类,cv是成员函数声明的cv-qualification.
所以你问的是等同于以下内容:
void bar(foo&);
void bar(foo&&);
void bar(const foo&);
void bar(const foo&&);
int main()
{
bar(foo());
}
Run Code Online (Sandbox Code Playgroud)
表达式foo()是一个类prvalue.
其次,非const左值参考版本不可行,因为prvalue不能绑定它.
这为我们提供了三种可行的重载决策功能.
每个都有一个隐式对象参数(const foo&,foo&&或const foo&&),因此我们必须对这三个进行排名以确定最佳匹配.
在所有三种情况下,它都是直接绑定的引用绑定.这在声明符/初始化(8.5.3)中描述.
三个可能的绑定(的排名const foo&,foo&&和const foo&&)在13.3.3.2.3中描述:
标准转换序列S1比标准转换序列S2更好的转换序列,如果
- S1和S2是引用绑定,并且都没有引用在没有ref-qualifier的情况下声明的非静态成员函数的隐式对象参数[此异常在此处不适用,它们都具有ref-qualifiers],并且S1绑定rvalue引用到rvalue [一个prvalue类是一个rvalue] ,S2绑定一个左值引用.
这意味着,foo&&和const foo&&更好的然后const foo&.
- S1和S2是引用绑定,引用引用的类型除了顶级cv限定符之外是相同的类型,并且S2引用的引用所引用的类型比cv限定的类型更具cv限定类型.参考由S1初始化.
这意味着foo&&更好const foo&&.
所以Clang是对的,这是GCC中的一个错误.超载排名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;
};
Run Code Online (Sandbox Code Playgroud)
GCC中的错误似乎纯粹适用于隐式对象参数(with ref-qualifiers),对于正常参数,它似乎使得排名正确,至少在4.7.2中.
| 归档时间: |
|
| 查看次数: |
2304 次 |
| 最近记录: |