Overload resolution with ref-qualifiers

后端 未结 1 1776
广开言路
广开言路 2020-12-01 12:17

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

相关标签:
1条回答
  • 2020-12-01 13:00

    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

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

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

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

    The expression foo() is a class 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.

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

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

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

    Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if

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

    This means that both foo&& and const foo&& are better then 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.

    This means that foo&& is better than const foo&&.

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

    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.

    0 讨论(0)
提交回复
热议问题