Типы возвратов трейлинга, decltype и const-ness

Я весело экспериментировал с новыми типами возврата в трейлинге, где у меня возникла проблема с этим (упрощенным) кодом

#include <list>

class MyContainer{
  std::list<int> ints;

  auto begin( ) -> decltype(ints.begin())
  {
    return ints.begin();
  }

  auto begin( ) const -> decltype(ints.begin())
  {
    return ints.begin();
  }
};

Игнорирую факт, насколько бессмыслен этот код. Важной частью является ошибка компилятора, возникающая при использовании GCC 4.6.1 (с флагом -std=c++0x):

In member function 'std::list<int>::iterator MyContainer::begin() const':
error: could not convert '((const MyContainer*)this)->MyContainer::ints.std::list<_Tp, _Alloc>::begin [with _Tp = int, _Alloc = std::allocator<int>, std::list<_Tp, _Alloc>::const_iterator = std::_List_const_iterator<int>]()' from 'std::list<int>::const_iterator {aka std::_List_const_iterator<int>}' to 'std::list<int>::iterator {aka std::_List_iterator<int>}'

Если вы не любитель ошибок с шаблонами, то короткая история состоит в том, что в теле const версии MyContainer::begin, выражение ints. begin() возвращает значение типа std::list::const_iterator (так как ints в таком контексте является const). Однако, decltype(ints.begin()) создает тип std::list::iterator, т.е. decltype игнорирует классификатор const метода begin при принятии решения о типе выражения. Неудивительно, что в результате возникает конфликт типов.

Это кажется мне ошибкой в компиляторе GCC. Имеет смысл только для того, чтобы decltype чтил классификатор const и выдавал тип const_iterator. Кто-нибудь может подтвердить или опровергнуть (может даже объяснить) это? Может быть, я что-то упускаю из виду в механике типа decltype, но это выглядит довольно прямолинейным сценарием.

Примечание: насколько я могу судить, такое же поведение имеет место не только для std::list, но и для любого типа, в котором функции-члены перегружены на const-ness, возвращающие несовместимые типы.

16
задан Xeo 27 January 2012 в 19:53
поделиться