Reputation: 177
Consider the following code:
#include<iostream>
#include<vector>
using namespace std;
class Foo {
public:
template< typename T>
operator vector< T >() const {
return vector< T >();
}
template< typename T>
operator T() const {
return T();
}
};
int main () {
Foo b;
vector< int > q = b;
q = b;
}
Compiling this with Clang or g++ using either of the two commands:
g++ test.cpp
clang++ test.cpp
Enabling C++11 features, however, it fails:
g++ --std=c++0x test.cpp
clang++ --std=c++11 test.cpp
The error message reads as follows:
test.cpp:20:5: error: use of overloaded operator '=' is ambiguous (with operand types 'vector<int>' and 'Foo')
q = b;
~ ^ ~
/usr/include/c++/4.6/bits/stl_vector.h:373:7: note: candidate function
operator=(vector&& __x)
^
/usr/include/c++/4.6/bits/stl_vector.h:362:7: note: candidate function
operator=(const vector& __x);
^
/usr/include/c++/4.6/bits/stl_vector.h:394:7: note: candidate function
operator=(initializer_list<value_type> __l)
^
1 error generated.
It is unclear to me why it works without C++11, while it fails with. Moveover, note that the line
vector< int > q = b; // In the main function, line 19
in the main function does not cause an error. Can anyone explain why it does not work, and what one can do to make it work with C++11?
Upvotes: 1
Views: 1277
Reputation: 283634
There's no compiler bug here. Your code is broken in C++11, because C++11 added more converting constructors and more overloads for the assignment operator.
This is the risk you run when you make a type that converts to absolutely anything (using templated conversion). Foo
is just as happy to convert itself to an initializer_list<int>
as a vector<int>
.
The reason that
vector<int> q = b;
works in Clang 3.1, while
vector<int> q(b);
fails, is that the first is copy-initialization, which requires an implicit conversion to vector<int>
followed by a copy-constructor call, while the second is direct-initialization which performs an explicit conversion. The set of candidates for implicit conversion is smaller, because constructors marked explicit
are removed, resolving the ambiguity.
The difference between Clang 3.0 and 3.1 is likely a library compliance fix, which marked additional constructors as explicit
, not a change to compiler behavior.
Upvotes: 2