Я весело экспериментировал с новыми типами конечного возврата, где столкнулся с проблемой с этим (упрощенным) кодом
#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<int>::const_iterator
(так как ints
- это const
в таком контексте). Однако decltype(ints.begin())
создает тип std::list<int>::iterator
, то есть decltype
игнорирует квалификатор const
метода begin
при определении типа выражения. Неудивительно, что конфликт типов является результатом.
Мне кажется, это ошибка в компиляторе GCC. decltype
имеет смысл только соблюдать квалификатор const
и производить тип const_iterator
. Кто-нибудь может подтвердить или опровергнуть (возможно, даже объяснить) это? Возможно, я что-то упускаю из механики decltype
, но это выглядит довольно простым сценарием.
Примечание: насколько я могу судить, такое же поведение сохраняется не только для std::list<int>
, но и для любого типа с функциями-членами, перегруженными на const
-ness, которые возвращают несовместимые типы.