std::back_inserter нуждается в const_reference в более старом GCC. Почему?

#c #stl #stl-algorithm

#c #stl #stl-алгоритм

Вопрос:

В настоящее время я просматриваю некоторый код, который может быть скомпилирован на более новых версиях GCC, но не на старых. В моем случае я использую std::back_inserter для std::copy переноса некоторых данных из одной структуры данных в пользовательскую структуру данных. Однако, если я забуду typedef value_type amp; const_reference typedef в этой пользовательской структуре данных, это не будет компилироваться в GCC 4.4. Тот же код компилируется и отлично выполняется в GCC 4.5.

В чем разница между этими двумя версиями компилятора, которая заставляет код компилироваться в одной версии, но не в другой. Я бы предположил, что это как-то связано с реализацией C 11, которая была намного менее полной в GCC 4.4. Вероятно, что-то с decltype или другим новым ключевым словом C 11, я бы предположил.

Также корректен ли этот код, если я использую std::back_inserter без определения const_reference типа? Обычно я думал, что нужно реализовать полный набор typedefs ( value_type , reference const_reference и т.д.), Чтобы быть совместимым с библиотекой STL-algorithms? Или я могу с уверенностью предположить, что если мой код компилируется в этом случае, я не вызываю ничего опасного (например, семантику перемещения, которая разрушила бы мою другую структуру данных).

Комментарии:

1. Для справки (чтобы помочь новичкам вроде меня сэкономить время): После того, как я добавил typedef Tamp; reference; typedef const Tamp; const_reference; в свою структуру данных, ошибка c2039 для back_inserter исчезла.

Ответ №1:

В стандарте (1998) говорится, что это std::back_insert_iterator необходимо Container::const_reference . В «24.4.2.1 классе шаблона back_insert_iterator», [lib.back.insert.iterator], говорится:

 back_insert_iterator<Container>amp;
operator=(typename Container::const_reference value);
  

Стандарт 2011 требует только Container::value_type ,

 back_insert_iterator<Container>amp;
operator=(const typename Container::value_typeamp; value);
back_insert_iterator<Container>amp;
operator=(typename Container::value_typeamp;amp; value);
  

Итак, чтобы быть совместимым с обеими версиями стандарта C , определите обе value_type и const_reference_type .

Как в GCC 4.4.6, так и в 4.5.1, определение operator= идентично ( libstdc -v3/include/bits/stl_iterator.h ):

   back_insert_iteratoramp;
  operator=(typename _Container::const_reference __value)
  {
    container->push_back(__value);
    return *this;
  }
  

и я получаю одинаковую ошибку с обоими компиляторами, возможно, вам нужно дважды проверить, используете ли вы правильные версии компилятора.

Комментарии:

1. Спасибо за разъяснение. В версии 4.5.2 это работает без типа const_reference, как я только что подтвердил. 4.4.4 все еще нуждается в этом.

2. @LiKao, в последних GCC совместимость с библиотекой C 0x включена по умолчанию. GCC4.5.2 немного более совместим :), чем GCC 4.4, в том смысле, что он использует const_reference только тогда, когда совместимость отключена, тогда как 4.4 использует ее безоговорочно.

3. @chill: Цитирую документацию текущей версии gcc : The default, if no C language dialect options are given, is -std=gnu 98. . Итак, вы уверены в том, что говорите?

Ответ №2:

Причина, по которой вам нужно const_reference определить для вашей структуры данных, заключается в том, что оператор присваивания в GCC 4.4 для типа аргумента lvalue в std::back_insert_iterator классе определен как:

 template<class Container>
back_insert_iterator<Container>amp; 
back_insert_iterator<Container>::operator= 
                  (typename Container::const_reference value);
  

Таким образом, const_reference должен быть разрешимый идентификатор в вашем классе-введите, чтобы правильно создать экземпляр оператора присваивания в std::back_insert_iterator шаблоне класса.

В GCC 4.5 это определение оператора присваивания для аргументов lvalue было изменено на

 template<class Container>
back_insert_iterator<Container>amp;
back_insert_iterator<Container>::operator=
                 (const typename Container::value_typeamp; value);
  

для поддержки новой спецификации C 11. Поскольку ваш код корректно компилируется с GCC 4.5, я предполагаю, что вы должны value_type правильно определить свою структуру данных.