具有ref-qualifier的过载解析 [英] Overload resolution with ref-qualifiers

查看:156
本文介绍了具有ref-qualifier的过载解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用ref限定的函数重载时,我从 GCC(4.8.1) Clang(2.9和trunk)得到不同的结果。考虑下面的代码:

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();
}

编译它并输出const rvalue,而 GCC 认为这是一个模糊的调用,两个const限定的函数都是最可行的候选。如果我提供所有4个重载,那么两个编译器输出非常量值

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

Note: The reason this actually matters is that the real code declares both const-qualified functions as 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. 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.

推荐答案

首先,对隐式对象参数进行处理作为根据13.3.1.4的正常参数:

Firstly, the implicit object parameter is treated as a normal parameter as per 13.3.1.4:


对于非静态成员函数,隐式对象参数的类型是

For non-static member functions, the type of the implicit object parameter is

- 对于没有ref-qualifier声明的函数,或者使用& ref-qualifier

— "lvalue reference to cv X" for functions declared without a ref-qualifier or with the & ref-qualifier

- 对于使用&&& ref-qualifier

— "rvalue reference to cv X" for functions declared with the && ref-qualifier

其中X是函数是成员的类,cv是成员
函数声明上的cv-qualification。

where X is the class of which the function is a member and cv is the cv-qualification on the member function declaration.

因此,您要求的内容相当于以下内容:

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());
}

表达式 foo()

The expression foo() is a class prvalue.

其次,非const常量引用版本是不可行的,因为prvalue不能绑定到它。

Secondly, the non-const lvalue reference version is not viable, as a prvalue cannot bind to it.

这使我们有三个可行的重载解析函数。

This leaves us with three viable functions for overload resolution.

每个都有一个隐式对象参数( const foo& ; foo&&& const foo&&&

Each has a single implicit object parameter (const foo&, foo&& or const foo&&), so we must rank these three to determine the best match.

在所有三种情况下,它都是一个直接绑定的引用绑定。这在声明器/初始化(8.5.3)中描述。

In all three case it is a directly bound reference binding. This is described in declarators/initialization (8.5.3).

三个可能的绑定的排名( const foo& foo&& const foo&&& / p>

The ranking of the three possible bindings (const foo&, foo&& and const foo&&) is described in 13.3.3.2.3:


标准转换序列 S1是比标准转换序列S2更好的转换序列 if


  • S1和S2是引用绑定,并且都不涉及没有ref-qualifier声明的非静态成员函数的隐式对象参数[此异常不适用于此处,它们都具有ref-qualifier], S1将右值引用绑定到右值 [类别prvalue是右值] 和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.

这意味着 foo&& const foo&&& const foo& 更好。



  • S1和S2是引用绑定,引用引用的类型是除顶级cv限定符之外的相同类型,由 S2引用初始化的引用比由S1引用的引用的类型更加cv限定。

  • 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.

这意味着 foo&&& const foo&&

So Clang是对的,这是GCC中的一个错误。 foo()。bar()的重载排序如下:

So Clang is right, and it is a bug in GCC. The overload ranking for foo().bar() is as follows:

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。

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.

这篇关于具有ref-qualifier的过载解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆