简体   繁体   English

使用ref限定符的过载分辨率

[英]Overload resolution with ref-qualifiers

While working with ref-qualified function overloads, I'm getting different results from GCC (4.8.1) and Clang (2.9 and trunk) . 在使用ref限定的函数重载时,我从GCC(4.8.1)Clang(2.9和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();
}

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. Clang编译它并输出"const rvalue" ,而GCC认为这是一个模棱两可的调用,两个const限定的函数都是最佳可行的候选者。 If I provide all 4 overloads, then both compilers output "non-const rvalue" . 如果我提供所有4个重载,则两个编译器都将输出"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. 我想知道哪个编译器(如果有)在做正确的事情,以及相关的标准部分在起作用。

Note: The reason this actually matters is that the real code declares both const-qualified functions as constexpr . 注意:这实际上很重要的原因是实际代码将两个const限定函数都声明为constexpr Of course, there is no output to std::cout and static_cast is used instead of std::move , so that they are valid constexpr definitions. 当然,没有输出到std::cout并且使用了static_cast而不是std::move ,因此它们是有效的constexpr定义。 And since in C++11 constexpr still implies const , the overload commented out in the sample code cannot be provided as it would redefine the const-qualified rvalue overload. 并且由于在C ++ 11中 constexpr仍然隐含const ,因此无法提供示例代码中注释的重载,因为它将重新定义const限定的右值重载。

Firstly, the implicit object parameter is treated as a normal parameter as per 13.3.1.4: 首先,根据13.3.1.4,将隐式对象参数视为普通参数:

For non-static member functions, the type of the implicit object parameter is 对于非静态成员函数,隐式对象参数的类型为

— “lvalue reference to cv X” for functions declared without a ref-qualifier or with the & ref-qualifier —“不带ref限定符或带有&ref限定符声明的函数的“对cv X的左值引用”

— “rvalue reference to cv X” for functions declared with the && ref-qualifier —“用&v引用限定符声明的函数的cv X的右值引用”

where X is the class of which the function is a member and cv is the cv-qualification on the member function declaration. 其中X是该函数是成员的类,而cv是该成员函数声明上的cv限定词。

So what you are asking is equivalent to the following: 因此,您要问的内容等同于以下内容:

void bar(foo&);
void bar(foo&&);
void bar(const foo&);
void bar(const foo&&);

int main()
{
    bar(foo());
}

The expression foo() is a class prvalue. 表达式foo()是类prvalue。

Secondly, the non-const lvalue reference version is not viable, as a prvalue cannot bind to it. 其次,非常量左值引用版本不可行,因为prvalue不能绑定到它。

This leaves us with three viable functions for overload resolution. 这为我们提供了三个可行的函数来解决过载。

Each has a single implicit object parameter ( const foo& , foo&& or const foo&& ), so we must rank these three to determine the best match. 每个都有一个隐式对象参数( const foo&foo&&const foo&& ),因此我们必须对这三个参数进行排名以确定最佳匹配。

In all three case it is a directly bound reference binding. 在所有三种情况下,它都是直接绑定的参考绑定。 This is described in declarators/initialization (8.5.3). 这在声明符/初始化(8.5.3)中进行了描述。

The ranking of the three possible bindings ( const foo& , foo&& and const foo&& ) is described in 13.3.3.2.3: 13.3.3.2.3中描述了三种可能的绑定( const foo&foo&&const foo&& )的排名:

Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if 如果满足以下条件,则标准转换序列S1比标准转换序列S2更好。

  • S1 and S2 are reference bindings and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier [this exception doesn't apply here, they all have ref-qualifiers], and S1 binds an rvalue reference to an rvalue [a class prvalue is an rvalue] and S2 binds an lvalue reference . S1和S2是引用绑定,都没有引用未声明ref限定符的非静态成员函数的隐式对象参数[此异常不适用于此处,它们都具有ref限定符], S1绑定了右值引用到一个右值 [一个类prvalue是一个右值] ,S2绑定一个左值引用

This means that both foo&& and const foo&& are better then const foo& . 这意味着foo&&const foo&&const foo&更好。

  • S1 and S2 are reference bindings, and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers . S1和S2是引用绑定,除了顶级cv限定符之外,引用所引用的类型是相同的类型,并且由S2初始化的引用所引用的类型比sc和s2所引用的类型更具cv资格。由S1初始化的引用为

This means that foo&& is better than const foo&& . 这意味着foo&&const foo&&更好。

So Clang is right, and it is a bug in GCC. 因此Clang是正确的,这是GCC中的错误。 The overload ranking for foo().bar() is as follows: 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;
};

The bug in GCC seems to apply purely to implicit object parameters (with ref-qualifiers ), for a normal parameter it seems to get the ranking correct, at least in 4.7.2. GCC中的错误似乎仅适用于隐式对象参数(使用ref-qualifiers ),对于正常参数而言,至少在4.7.2中,该排名似乎正确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用ref-qualifiers重载模板方法的分辨率 - Overload resolution of template methods with ref-qualifiers STL容器的右值ref限定词 - rvalue ref-qualifiers for STL containers 用cv-qualifiers和ref-qualifiers实现std :: is_function - Implementation of std::is_function with cv-qualifiers and ref-qualifiers 调用重载限定符成员函数的重载是不明确的 - call of overloaded with ref-qualifiers member function is ambiguous 在C ++中,ref-qualifiers是否表达了一种子类型? - In C++, do ref-qualifiers express a form of subtyping? 对于不同的ref-qualifiers,运算符重载的结果的类型特征 - type traits for result of operator overloaded for different ref-qualifiers 标准库类型的赋值运算符的ref-qualifiers - ref-qualifiers for the assignment operator of standard library types 如何比较参数包中的类型(包括引用限定符)和 std::function 参数的类型 - How to compare types (including ref-qualifiers) in a parameter pack and the types of std::function parameters 重载决议中的约束是否受类型限定符差异的影响? - Are constraints in overload resolution affected by difference it type qualifiers? 可以在ref限定符上明确默认/删除函数重载吗? - Can explicitly defaulted / deleted functions overload on ref qualifiers?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM