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?
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).
Foois just as happy to convert itself to aninitializer_list<int>as avector<int>.The reason that
works in Clang 3.1, while
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 markedexplicitare 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.