Eclipse CDT:无法解析foreach-loop中的'begin'和'end'符号

问题描述 投票:1回答:2

当我想直接迭代函数返回的数据时,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索引器的其他问题,但答案并没有解决我的问题:

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中的(已知)错误?

c++11 foreach eclipse-cdt
2个回答
1
投票

如果我们看一下begin的定义

inline MyIterator begin(Handle &it) { return MyIterator(it); }

我们看到它引用了一个非常量对象。这意味着您无法将临时对象传递给该函数。就像直接使用do_something()时会发生什么。快速解决方案是添加一个带有右值引用的重载:

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


0
投票

有问题的代码实际上符合要求。它汇编了最新版本的gcc和clang。

另一个答案中的缺陷是它没有考虑编译器在基于范围的for循环上执行的重写。

[stmt.ranged] p1说:

基于范围的声明

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

© www.soinside.com 2019 - 2024. All rights reserved.