Eclipse CDT:无法解析 foreach 循环中的 'begin' 和 'end' 符号
Eclipse CDT: cannot resolve 'begin' and 'end' symbols in foreach-loop
每当我想直接迭代函数返回的数据时,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 中的(已知)错误?
如果我们看一下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
returns 按值计算。这意味着每次调用 do_something
都会 return 一个单独的对象,如果 do_something
被调用不止一次,您将拥有具有不同数据的不同对象。
另请注意,如果您需要通用类型,请改用 std::iterator
have been deprecated in the C++17 standard. You should specialize std::iterator_traits
。
有问题的代码实际上是符合规范的。它使用最新版本的 gcc 和 clang 编译。
另一个答案的缺陷在于它没有考虑编译器对基于范围的 for 循环执行的重写。
[stmt.ranged] p1
说:
The range-based for statement
for ( init-statement_opt for-range-declaration : for-range-initializer) statement
is equivalent to
{
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,很快就会修复。
每当我想直接迭代函数返回的数据时,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 中的(已知)错误?
如果我们看一下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
returns 按值计算。这意味着每次调用 do_something
都会 return 一个单独的对象,如果 do_something
被调用不止一次,您将拥有具有不同数据的不同对象。
另请注意,如果您需要通用类型,请改用 std::iterator
have been deprecated in the C++17 standard. You should specialize std::iterator_traits
。
有问题的代码实际上是符合规范的。它使用最新版本的 gcc 和 clang 编译。
另一个答案的缺陷在于它没有考虑编译器对基于范围的 for 循环执行的重写。
[stmt.ranged] p1
说:
The range-based for statement
for ( init-statement_opt for-range-declaration : for-range-initializer) statement
is equivalent to
{ 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,很快就会修复。