неявное преобразование конструктора работает с явным вектором :: вектор, только иногда - PullRequest
2 голосов
/ 22 декабря 2009

Мне нравится инициализировать 2-мерные массивы как vector<vector<int> >(x,y). x передается конструктору vector<vector<int> >, а y передается конструктору vector<int>, x раз. Хотя это кажется запрещенным в C ++ 03, поскольку конструктор explicit, он всегда работает, даже на Comeau. Я также могу позвонить vector::assign, как это. Но почему-то не vector::push_back.

        vector< vector< int > > v( 20, 40 ); // OK: convert 40 to const T&
        v.assign( 30, 50 ); // OK
        v.push_back( 2 ); // error: no conversion, no matching function, etc.

По каким-то причинам первые два примера действительно соответствуют? Почему я могу конвертировать 40 и 50, но не 2?


Эпилог: см. http://gcc.gnu.org/onlinedocs/libstdc++/ext/lwg-defects.html#438, почему большинство компиляторов допускают это, но стандарт смещается в другую сторону.

Ответы [ 4 ]

5 голосов
/ 22 декабря 2009

Ваше предположение о том, что 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, которое возможно присутствует в конструкторе элемента вектора.

1 голос
/ 22 декабря 2009

vector< vector< int > > v( 20, 40 ); используйте конструктор, с которым вы, возможно, не знакомы. Конструктор называется здесь vector(iterator start, iterator end);

Внутренне он специализируется на итераторе int, поэтому первый параметр обрабатывается как count, а второй параметр - это значение для инициализации вектора. Поскольку при присвоении второго параметра значению вектора есть приведение, то конструктор внутреннего vector<T>(int, const T&) будет вызываться со значением 40. Следовательно, внутренний вектор создается с 40 0.

1 голос
/ 22 декабря 2009

Действительно ли первые два примера по какой-то причине соответствуют?

Они не соответствуют компилятору, который я только что попробовал. (gcc 4.4.1)

Почему я могу конвертировать 40 и 50, но не 2?

Поскольку первые две строки не соответствуют стандарту, только Comeau может знать, почему их несоответствие несовместимо.

Не случайно, что стандарт требует явного преобразования типов int в произвольные векторы. Это сделано для предотвращения путаницы кода.

0 голосов
/ 22 декабря 2009

Ваши примеры не соответствуют. Конструктор является явным, как вы сказали, поэтому вы не можете передавать int (y) вместо вектора для конструктора (и y не передается "x раз" в векторный конструктор: второй параметр создается только один раз, для инициализации вставленные объекты). Ваши примеры не работают в gcc (4.4 и 4.5).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...