Trailing return types, decltype and const-ness
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. d开发者_开发百科ecltype
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.
精彩评论