75

Given all three functions, this call is ambiguous.

int f( int );
int f( int && );
int f( int const & );

int q = f( 3 );

Removing f( int ) causes both Clang and GCC to prefer the rvalue reference over the lvalue reference. But instead removing either reference overload results in ambiguity with f( int ).

Overload resolution is usually done in terms of a strict partial ordering, but int seems to be equivalent to two things which are not equivalent to each other. What are the rules here? I seem to recall a defect report about this.

Is there any chance int && may be preferred over int in a future standard? The reference must bind to an initializer, whereas the object type is not so constrained. So overloading between T and T && could effectively mean "use the existing object if I've been given ownership, otherwise make a copy." (This is similar to pure pass-by-value, but saves the overhead of moving.) As these compilers currently work, this must be done by overloading T const & and T &&, and explicitly copying. But I'm not even sure even that is strictly standard.

2
  • 1
    You state int&& in the code but then generalise to T&& in the question, despite them being different. Which is it? Commented Jul 31, 2013 at 4:44
  • 2
    @Rapptz I only said T when talking about possible meaning in real-world use. I don't mean to suggest perfect forwarding, that's a completely different ballgame. Commented Jul 31, 2013 at 4:45

1 Answer 1

65

What are the rules here?

As there is only one parameter, the rule is that one of the three viable parameter initializations of that parameter must be a better match than both the other two. When two initializations are compared, either one is better than the other, or neither is better (they are indistinguishable).

Without special rules about direct reference binding, all three initializations mentioned would be indistinguishable (in all three comparisons).

The special rules about direct reference binding make int&& better than const int&, but neither is better or worse than int. Therefore there is no best match:

S1    S2
int   int&&         indistinguishable
int   const int&    indistinguishable
int&& const int&    S1 better

int&& is better than const int& because of 13.3.3.2:

S1 and S2 are reference bindings (8.5.3) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and S1 binds an rvalue reference to an rvalue and S2 binds an lvalue reference.

But this rule does not apply when one of the initializations is not a reference binding.

Is there any chance int && may be preferred over int in a future standard? The reference must bind to an initializer, whereas the object type is not so constrained. So overloading between T and T && could effectively mean "use the existing object if I've been given ownership, otherwise make a copy."

You propose to make a reference binding a better match than a non-reference binding. Why not post your idea to isocpp future proposals. SO is not the best for subjective discussion / opinion.

Sign up to request clarification or add additional context in comments.

3 Comments

So both gcc and clang are right: if f(int) and f(int&&) are in consideration, the overload is ambiguous, and same for f(int) and f(int const&).
@Yakk: "if f(int) and f(int&&) are in consideration, the overload is ambiguous" Almost. If there is no best match, the overload is ambiguous. Suppose f(int), f(int&&) and f(double) were viable for a call of f(2.0). f(double) is the best match even though f(int) and f(int&&) are in consideration.
"any chance int && may be preferred over int in a future standard?" - "You propose to make a reference binding a better match than a non-reference binding." - I'd say you expect int&& and int not be ambiguous because rvalue and lvalue are explained as kind of types: "...std::move are nothing but casts" and "'rvalue reference' is a kind of type". E.g. int x=5; f(std::move(x)) should match to f(int&&) not f(int), but it does not, it's ambiguous, while f(x) matches f(int) no problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.