Your assumption that Como implicitly calls the constructor explicit is most likely incorrect. The behavior is really broken, but the problem is different.
I suspect that this is a mistake in implementing the standard library that comes with Comeau and not with the main Comeau compiler (although in this case the line is blurry).
If you create a quick mannequin class that has constructor properties similar to std::vector , and try the same, you will find that the compiler correctly refuses to execute the construct.
The most likely reason it takes your code is because of the well-known formal ambiguity of the two-parameter constructor std::vector . It can be interpreted as a constructor (size, initial value)
explicit vector(size_type n, const T& value = T(), const Allocator& = Allocator());
or as a template constructor (begin, end) with the last one accepting two iterators
template <class InputIterator> vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
The standard specification of the library explicitly states that when two integral values are used as arguments, the implementation must somehow make sure that the selected constructor is selected, i.e. (size, initial value) . How this is done does not matter. This can be done at the library level, it can be hardcoded in the main compiler. This can be done in any other way.
However, in response to arguments ( 20, 40 ) , the Comeau compiler seems to mistakenly select and instantiate the last constructor using InputIterator = int . I don’t know how he manages to compile a specialized version of the constructor, since integral values cannot and will not work as iterators.
If you try this one
vector< vector< int > > v( 20U, 40 );
you will find that the compiler now reports an error (since it can no longer use the version of the constructor's two-terator), and explicit in the first constructor does not allow you to convert 40 to std::vector .
The same thing happens with assign . This, of course, is a drawback of the Como implementation, but, again, experiments show that, most likely, the required behavior should have been performed at the library level (the main compiler seems to work fine), and somehow it was done wrong.
In my second thought, I see that the main idea in my explanation is correct, but the details are wrong. Also, I could be wrong in calling him a problem in Como. It is possible that Como is here.
The standard says in 23.1.1 / 9 that
constructor
template <class InputIterator> X(InputIterator f, InputIterator l, const Allocator& a = Allocator())
should have the same effect as:
X(static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l), a)
if InputIterator is an integral type
I suspect that if the above is interpreted literally, the compiler is allowed to assume that explicit static_cast meant there (well ... so to speak), and the code is legal for the same reason static_cast< std::vector<int> >(10) is legal , despite the fact that the corresponding constructor is explicit . The presence of static_cast is that it allows the compiler to use the explicit constructor.
If the Comeau compiler’s behavior is correct (and I suspect that it is indeed correct as required by the standard), I wonder if this was the committee’s goal to leave such a loophole open and allow the implementation to work on the explicit constraint, possibly present in the vector element constructor .