尾随返回类型,decltype和constness [英] Trailing return types, decltype and const-ness

查看:191
本文介绍了尾随返回类型,decltype和constness的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 

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 标志)时产生的编译器错误:


$ b $在成员函数'std :: list< int> :: iterator MyContainer :: begin()const':
错误:无法转换'((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>}'到'std :: list& aka std :: _ List_iterator< int>}'

如果你不是模板,简短的故事是,在 const 版本 MyContainer :: begin 的正文中,表达式 ints.begin()返回类型 std :: list< int> :: const_iterator 在这样的上下文中,c> ints 是 const )。然而, decltype(ints.begin())产生 std :: list< int> :: iterator begin const 限定符 code>方法决定表达式的类型。不出所料,类型冲突是结果。



这似乎是一个在GCC编译器中的错误。只有 decltype 才能满足 const 限定符并产生 const_iterator 类型。任何人都可以确认或否认(甚至可以解释)这个?也许我可以忽略 decltype 的机制,但这看起来像一个非常简单的场景。



注意:就我可以告诉,同样的行为不仅适用于 std :: list< int> ,但对于任何类型成员函数重载

解决方案

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


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


但这是最近一次工作草案和N3291之间的最近变化。所以GCC恰好不到6个月前;这是将代码写入移动规范的危险。


I was merily experimenting with the new trailing return types, where I hit a problem with this (simplified) code

#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();
  }
};

Ignore the fact of how pointless this code is. The important part is the compiler error generated when using GCC 4.6.1 (with -std=c++0x flag):

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>}'

In case you're not of fan of error involving templates, the short story is that in the body of the const version of MyContainer::begin, the expression ints.begin() returns a value of type std::list<int>::const_iterator (since ints is const in such a context). However, decltype(ints.begin()) produces the type std::list<int>::iterator, i.e. decltype ignores the const qualifier of the begin method when deciding the type of the expression. Unsurprisingly, a conflict in types is the result.

This seems to me to be a bug in the GCC compiler. It would only make sense for decltype to honor the const qualifier and produce the const_iterator type. Can anyone confirm or deny (maybe even explain) this? Maybe I am overlooking something in the mechanics of decltype, but this looks like a pretty straightforward scenario.

Note: as far as I can tell, the same behaviour holds not only for std::list<int>, but for any type with member functions overloaded on const-ness which return incompatible types.

解决方案

You are correct, this is a bug. According to N3291, section 5.1.1, paragraph 3:

If a declaration declares a member function or member function template of a class X, the expression this is a prvalue of type "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq and the end of the function-definition, member-declarator, or declarator. It shall not appear before the optional cv-qualifier-seq and it shall not appear within the declaration of a static member function (although its type and value category are defined within a static member function as they are within a non-static member function). [Note: this is because declaration matching does not occur until the complete declarator is known. —end note ] Unlike the object expression in other contexts, *this is not required to be of complete type for purposes of class member access (5.2.5) outside the member function body. [Note: only class members declared prior to the declaration are visible. —end note ]

But this was a recent change between the last working draft and N3291. So GCC was right less than 6 months ago; that's the danger of writing code to a moving specification.

这篇关于尾随返回类型,decltype和constness的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆