This is a rather tricky question, and it might be the case that VisualStudio is right and Comeau wrong (this seems really hard to believe).
The standard if read word by word, defines that vector constructor in terms of the copy constructor (see quote), and that literally means that the object obtained by dereferencing the iterator must first be converted into the type T and then the copy constructor should be called. At this point, with an explicit constructor the code should not compile.
It seems reasonable to expect an implementation, on the other hand, to directly call a constructor taking as argument the dereferenced iterator, in which case the constructor call would be explicit and thus the code should compile. This would go against the exact wording in the quote below, as the copy constructor is defined for a given type T as a constructor that taking a single possibly constant reference to an object of type T.
I cannot think of any reasonable argument not to use the Comeau approach, and my believe (this is just personal opinion) is that the wording in the standard with respect to the complexity of the vector constructor should probably be restated as requiring only N calls to the appropriate T constructor, where appropriate would have to be defined as the constructor that matches the call T( *first )
(that is, either a constructor taking an InputIterator::value_type
(by value or possibly constant reference), or the T copy constructor after an implicit conversion from InputIterator::value_type
to T.
23.2.4.1 [lib.vector.cons]/1
Complexity: The constructor template vector(InputIterator
first, InputIterator last) makes only
N calls to the copy constructor of T
(where N is the distance between
first and last) and no reallocations
if iterators first and last are of
forward, bidirectional, or random
access categories. It makes order N
calls to the copy constructor of T and
order log N reallocations if they are
just input iterators.
I would like to know how the VS compiler behaves when given:
struct T1;
struct T2 {
operator T1 ();
};
struct T1 {
T1( T2 const & ) { std::cout << "T1(T2)" << std::endl; }
};
T2::operator T1() {
std::cout << "T2::operator T1" << std::endl;
return T1(*this);
}
int main() {
std::vector<T2> v2;
v2.push_back( T2() );
std::vector<T1> v1( v2.begin(), v2.end() );
}
With g++ the result is that T2::operator T1
is not called, but rather the elements in v1
are constructed directly from the elements in v2
. I would assume that with VS the compiler would use T2::operator T1
to convert from each element in v2
to a T1 element and then call the copy constructor. Is that so?