Ваше предположение о том, что Comeau неявно вызывает конструктор explicit
, скорее всего неверно. Поведение действительно нарушено, но проблема в другом.
Я подозреваю, что это ошибка в реализации стандартной библиотеки, которая поставляется с Comeau, а не с самим базовым компилятором Comeau (хотя линия в этом случае размыта).
Если вы создадите быстрый фиктивный класс со свойствами конструктора, аналогичными std::vector
, и попробуете то же самое, вы обнаружите, что компилятор правильно отказывается выполнять построение.
Наиболее вероятной причиной, по которой он принимает ваш код, является известная формальная неоднозначность двухпараметрического конструктора std::vector
. Его можно интерпретировать как (size, initial value)
конструктор
explicit vector(size_type n, const T& value = T(),
const Allocator& = Allocator());
или (begin, end)
конструктор шаблона с последним принятием двух итераторов
template <class InputIterator>
vector(InputIterator first, InputIterator last,
const Allocator& = Allocator());
В спецификации стандартной библиотеки прямо указано, что, когда в качестве аргументов используются два целочисленных значения, реализация должна каким-то образом удостовериться, что сформированный конструктор выбран, т.е. (size, initial value)
. Как это сделано - не имеет значения. Это может быть сделано на уровне библиотеки, это может быть жестко задано в основном компиляторе. Это можно сделать любым другим способом.
Однако в ответ на ( 20, 40 )
аргументы компилятор Comeau, по-видимому, ошибочно выбирает и создает экземпляр последнего конструктора с помощью InputIterator = int
. Я не знаю, как ему удается скомпилировать специализированную версию конструктора, поскольку целочисленные значения не могут и не будут работать в качестве итераторов.
Если вы попробуете это
vector< vector< int > > v( 20U, 40 );
вы обнаружите, что компилятор теперь сообщает об ошибке (поскольку он больше не может использовать двух-итераторную версию конструктора), а explicit
в первом конструкторе предотвращает его преобразование 40
в std::vector
.
То же самое происходит с assign
. Это, безусловно, дефект реализации Comeau, но, опять же, эксперименты показывают, что, скорее всего, требуемое поведение должно было выполняться на уровне библиотеки (основной компилятор, кажется, работает нормально), и каким-то образом это было сделано неправильно.
Со второй мысли я вижу, что основная идея в моем объяснении верна, но детали неверны. Кроме того, я могу ошибаться, называя это проблемой в Комо. Возможно, Комо прямо здесь.
Стандарт говорит в 23.1.1 / 9, что
конструктор
template <class InputIterator>
X(InputIterator f, InputIterator l, const Allocator& a = Allocator())
должен иметь такой же эффект, как:
X(static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l),
a)
, если InputIterator является целочисленным типом
Я подозреваю, что если вышеизложенное интерпретируется буквально, компилятору разрешается предполагать, что там подразумевается явное static_cast
(ну ... так сказать), и код допустим по той же причине static_cast< std::vector<int> >(10)
допустимо, несмотря на то, что соответствующий конструктор является explicit
. Наличие static_cast
позволяет компилятору использовать конструктор explicit
.
Если поведение компилятора Comeau правильное (и я подозреваю, что оно действительно корректно, как того требует стандарт), мне интересно, было ли намерение комитета оставить такую лазейку открытой и позволить реализациям работа вокруг ограничения explicit
, которое возможно присутствует в конструкторе элемента вектора.