当我想直接遍历函数返回的数据时,eclipse CDT的索引器无法正确识别foreach循环中所需的'end'和'begin'符号。当我第一次将结果放入一个临时变量时,它会起作用。
MWE:
#include "mwe.h"
int main(int argc, char **argv) {
auto tmp = do_something();
for(auto &x : tmp){ } //Working
for(auto &x : do_something()){ } //Symbol 'end'/'begin' could not be resolved
}
mwe.h:
#include<iterator>
class X { };
class Handle { };
class MyIterator: public std::iterator<X, std::input_iterator_tag> {
public:
explicit MyIterator(Handle &iter) : iter_(&iter) { }
MyIterator() { }
MyIterator &operator++() { return *this; }
MyIterator operator++(int) { return *this; }
X &operator*() { return x; }
X *operator->() { return &**this; }
friend bool operator==(MyIterator a, MyIterator b) { return true; }
friend bool operator!=(MyIterator a, MyIterator b) { return false; }
private:
Handle *iter_;
X x;
};
inline MyIterator begin(Handle &it) { return MyIterator(it); }
inline MyIterator end(Handle &) { return MyIterator(); }
Handle do_something() { return Handle(); }
代码可以编译并且没有错误,只有索引器告诉我它找不到符号。也就是说,解决此问题并不是真正必要,但这很烦人。
补充说明:我已经检查了CDT中有关Indexer的许多其他问题,但是答案并不能解决我的问题:
Eclipse CDT Indexer does not fully recognize c++11
Eclipse CDT: Symbol 'cout' could not be resolved
https://www.eclipse.org/forums/index.php/t/636348/
代码是否存在问题,还是CDT中的(已知)错误?
答案 0 :(得分:1)
如果我们看看begin
inline MyIterator begin(Handle &it) { return MyIterator(it); }
我们看到它引用了一个非常量对象。这意味着您不能将临时对象传递给该函数。就像直接使用do_something()
时发生的情况一样。快速的解决方案是添加一个带有 rvalue引用的重载:
inline MyIterator begin(Handle &&it) { return MyIterator(it); }
// ^^
// Note double ampersand here
尽管您的代码还有其他可能的陷阱,尤其是因为do_something
按值返回。这意味着每次对do_something
的调用都将返回一个单独的对象,并且如果多次调用do_something
,您将拥有具有不同数据的不同对象。
还要注意,std::iterator
在C ++ 17标准中已被弃用。如果要使用通用类型,则应该专门使用std::iterator_traits
。
答案 1 :(得分:0)
所讨论的代码实际上是符合要求的。它可以使用最新版本的gcc和clang进行编译。
另一个答案的缺陷在于,它没有考虑到编译器对基于范围的for循环执行的重写。
[stmt.ranged] p1
说:
基于范围的for语句
for ( init-statement_opt for-range-declaration : for-range-initializer) statement
等同于
{ init-statement_opt auto &&__range = for-range-initializer ; auto __begin = begin-expr ; auto __end = end-expr ; for ( ; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } }
因此,在这种情况下,for(auto &x : do_something()){ }
被重写为:
{
auto &&__range = do_something();
auto __begin = begin(__range);
auto __end = end(__range);
for ( ; __begin != __end; ++__begin ) {
auto &x = *__begin;
}
}
请注意,调用begin()
和end()
的实际参数不是表达式do_something()
本身,而是一个隐藏的(名义上的)变量__range
。由于__range
是一个命名变量,因此它是表达式上下文中的左值,并且begin()
和end()
的左值引用参数将成功绑定到它。>
Eclipse CDT在此代码上出现错误是一个错误,我只是filed,并将很快修复。