Eclipse CDT:无法在foreach循环中解析'begin'和'end'符号

时间:2018-08-20 09:18:41

标签: c++11 foreach eclipse-cdt

当我想直接遍历函数返回的数据时,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中的(已知)错误?

2 个答案:

答案 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,并将很快修复。