尾随返回类型,decltype和const-ness

时间:2011-08-31 10:00:19

标签: c++ c++11 const-correctness decltype trailing-return-type

我正在试验新的尾随返回类型,我遇到了这个(简化的)代码的问题

#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方法的decltype限定符,以确定其类型表达方式。不出所料,结果就是类型冲突。

在我看来,这是GCC编译器中的一个错误。只有const尊重const_iterator限定符并生成decltype类型才有意义。任何人都可以确认或否认(甚至可以解释)这个吗?也许我忽略了std::list<int>的机制,但这看起来非常简单。

注意:据我所知,同样的行为不仅适用于const,而且适用于在{{1}}上重载成员函数的任何类型 - 返回不兼容的类型。

1 个答案:

答案 0 :(得分:10)

你是对的,这是一个错误。根据N3291,第5.1.1节,第3段:

  

如果声明声明了类X的成员函数或成员函数模板,则表达式是可选的cv-qualifer-seq和结尾之间的类型为“指向cv-quali fi er-seq X的指针”的prvalue。 function-de fi nition,member-declarator或declarator。它不应出现在可选的cv-quali-seq之前,它不应出现在静态成员函数的声明中(尽管它的类型和值类别是在静态成员函数中定义的,因为它们在非静态成员函数中) 。 [注意:这是因为在完整的声明符已知之前不会发生声明匹配。 -end note]与其他上下文中的对象表达式不同,*为了成员函数体之外的类成员访问(5.2.5),这不需要是完整类型。 [注意:只有在声明之前声明的类成员才可见。 - 后注]

但这是最近一份工作草案与N3291之间的最新变化。所以GCC在不到6个月前是对的;这就是将代码写入移动规范的危险。