Explicit C ++ Constructors and Iterators

Consider the following code:

#include <vector> struct A { explicit A(int i_) : i(i_) {} int i; }; int main() { std::vector<int> ints; std::vector<A> As(ints.begin(), ints.end()); } 

Should the aforementioned compilation? I feel this should not, because the constructor is explicit marked.

Microsoft Visual C ++ agrees with a clear error message: cannot convert from 'int' to 'const A'; Constructor for struct 'A' is declared 'explicit' cannot convert from 'int' to 'const A'; Constructor for struct 'A' is declared 'explicit'

However, using the Comau online compiler , the code compiles successfully.

What is right?

Edit:

Interestingly, changing vector to set (after adding operator < to A) causes both compilers to throw an error.

However, changing vector<int> to map<int, int> and vector<A> to map<A, A> forces both compilers to accept the code!

+7
c ++ iterator constructor explicit
source share
6 answers

I looked at the implementation of the GCC STL and should have similar behavior. That's why.

  • The elements of a vector initialized by a generic function template that takes any two types X and V and calls new( p ) X( v ) , where V is V (I rephrase a bit). This allows an explicit conversion.
  • The set or map elements are initialized by the private member function _tree<T,…> , which specifically expects the transmission of T const & . This member function is not a template (in addition to being a member of the template), therefore, if the initial value cannot be implicitly converted to T , the call will fail. (Again, I simplify the code.)

The standard does not require that work with an explicit conversion or that an implicit conversion does not work when initializing a container with a range. It just says that the range is copied to the container. Definitely ambiguous for your purpose.

Amazing ambiguity exists, given how they have already improved the standard, addressing issues such as

+3
source share

I think this will depend on how std::vector<A> As(Iterator,Iterator) is implemented in your specific STL implementation.

+1
source share

This is a rather complicated question, and perhaps VisualStudio is right, and Como is wrong (it seems very hard to believe).

The standard, if you read by word, defines this vector constructor in terms of the copy constructor (see the citation), and this literally means that the object obtained by dereferencing the iterator must first be converted to type T, and then the constructor must be called. At this point, the code should not compile with the explicit constructor.

It seems reasonable to expect that the implementation, on the other hand, will directly call the constructor, which takes the dereferenced iterator as an argument, in which case the constructor call will be explicit and therefore the code must be compiled. This will contradict the exact wording in the quotation below, since the copy constructor is defined for a given type T as a constructor that accepts the only possible permanent reference to an object of type T.

I can’t come up with a reasonable argument, so as not to use Comow’s approach, and I think (this is just a personal opinion) that the wording in the standard regarding the complexity of a vector constructor should probably be adjusted as only N needs to refer to the corresponding constructor T, where necessary, should be defined as a constructor that matches the call T( *first ) (ie, either a constructor that takes InputIterator::value_type (by value or may permalink) or copy constructor T n follows an implicit conversion from InputIterator::value_type in T.

23.2.4.1 [lib.vector.cons] / 1

Difficulty: the vector of the constructor template (InputIterator first InputIterator) does only N invokes the copy constructor T (where N is the distance between the first and last) and redistribution if the iterators are the first and last of the forward, bidirectional or random access categories. This makes the order of N invokes the copy constructor T and the order of registration of N redistributions if they simply enter iterators.

I would like to know how the VS compiler behaves:

 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 not called, and elements from v1 are built directly from elements in v2 . I would suggest that with VS, the compiler would use T2::operator T1 to convert from each element in v2 to T1 element, and then call the copy constructor. This is true?

+1
source share

It really comes down to the question of how the STL library is implemented, and not the problem of language specification. There is nothing in the language specification that would prevent it from working, and there is nothing that would require it to work.

If stl :: vector constructor was written to attempt an implicit conversion using the assignment operator, then it will fail. It is more likely that the Microsoft STL implementation uses return value optimization during initialization through a constructor call, in which case this code will work fine.

It is important to note that the only reason this works is that the stl :: vector template constructor is templated, and the only requirement is that it is an input_iterator or, more precisely, supports all the necessary functions of the input iterator.

I would also like to point out that this is a prime example of why it is often difficult to write cross-platform code. Sometimes you have problems when no compiler necessarily deviates from the locale, but the code is still not portable.

+1
source share

This code does not compile in Como:

 class Foo { public: explicit Foo(int bar) { } }; class Bar { void DoStuff(Foo foo){ } void DoStuff2() { DoStuff(4); } }; 

Error message:

 "ComeauTest.c", line 16: error: no suitable constructor exists to convert from "int" to "Foo" DoStuff(4); ^ 1 error detected in the compilation of "ComeauTest.c". 

Thus, at the entry level, the online compiler supports explicit constructors. It must be related to vector / iterators.

EDIT . However, this compiles:

 Foo foo = (Foo)5; 

This is an explicit conversion, so OK. My guess is that the Como bill class explicitly uses the constructor somewhere where there is no Microsoft library.

More information on explicit constructors - http://www.glenmccl.com/tip_023.htm

0
source share

Yes, it must compile. If the constructor is not used, then its obviousness is not a problem.

0
source share

All Articles