This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
__rvalref overloads causing ambiguities
- From: Jonathan Wakely <cow at compsoc dot man dot ac dot uk>
- To: chris jefferson <caj at cs dot york dot ac dot uk>
- Cc: libstdc++ at gcc dot gnu dot org
- Date: Wed, 20 Jul 2005 17:35:27 +0100
- Subject: __rvalref overloads causing ambiguities
Hi Chris,
It looks like your rvalue references that provide move semantics
can cause ambiguous overloads.
This is rejected using an (almost) up-to-date compiler with the so_7
branch:
#include <vector>
struct A
{
template <typename B> operator B() const
{
return B();
}
};
int main()
{
A a;
std::vector<int> v;
v = a; // ERROR
}
The problem is that "template <class B> A::operator B() const" could be
called with [B = vector<int>] or with [B = rvalref<vector<int> >] and
there's no reason to prefer either of the conversions.
This isn't just academic, it breaks Boost.Assign:
http://tinyurl.com/cs4c4#assign-list_inserter-gcc-so7
http://tinyurl.com/cs4c4#assign-list_of-gcc-so7
http://tinyurl.com/cs4c4#numeric/ublas-test3-gcc-so7
(But apart from those three, all other Boost tests behave the same as
with normal mainline libstdc++, which is good.)
Could you add another level of indirection, so that going from A to
rvalref<vector> would require two user-defined conversions (which won't
happen implicitly) ?
I'm not sure you can, since "A::operator B" will always be able to match
rvalref<...> by a single conversion, and finding the overload set happens
before access-checking or checking whether a suitable ctor exists, or
most other reasons why the conversion to rvalref might fail.
To remove the rvalref overload from the overload set you'd have to use
SFINAE, but I think it would need A to be changed, which you can't
require since it's in user code.
This wouldn't be an issue with real rvalue refs in the language, since
there's no ambiguity between operator=(const vector&) and
operator=(vector&&) because both would use the same conversion from A to
vector<...>, and then the right one would be chosen based on the
"rvalue-ness" of the returned object.
Any clever ideas?
N.B. you get the same ambiguity for constructors that have an rvalref
overload:
A a;
std::vector<int> v(a); // ERROR
However, this works:
A a;
std::vector<int> v = a;
because to use the rvalref ctor would require two user-defined
conversions (A to rvalref, then rvalref to vector). At least, that's
how I understand it.
jon