C++11 Eclipse CDT:无法解析';开始';和';结束';foreach循环中的符号
每当我想要直接迭代函数返回的数据时,EclipseCDT的索引器不能正确识别foreach循环中所需的“end”和“begin”符号。当我第一次将结果放入一个临时变量时,它就起作用了 MWE: mwe.h:C++11 Eclipse CDT:无法解析';开始';和';结束';foreach循环中的符号,c++11,foreach,eclipse-cdt,C++11,Foreach,Eclipse Cdt,每当我想要直接迭代函数返回的数据时,EclipseCDT的索引器不能正确识别foreach循环中所需的“end”和“begin”符号。当我第一次将结果放入一个临时变量时,它就起作用了 MWE: mwe.h: #include<iterator> class X { }; class Handle { }; class MyIterator: public std::iterator<X, std::input_iterator_tag> { public: ex
#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(); }
#包括
类X{};
类句柄{};
类MyIterator:public std::iterator{
公众:
显式MyIterator(Handle&iter):iter(iter&iter){
MyIterator(){}
MyIterator&运算符++(){return*this;}
MyIterator运算符++(int){return*this;}
X&运算符*(){return X;}
X*运算符->(){return&**this;}
friend bool运算符==(MyIterator a,MyIterator b){return true;}
友元布尔运算符!=(MyIterator a,MyIterator b){return false;}
私人:
手柄*iter;
X;
};
内联MyIterator begin(Handle&it){返回MyIterator(it);}
内联MyIterator end(句柄&){return MyIterator();}
Handle do_something(){return Handle();}
代码编译和工作时没有错误,只有索引器告诉我它找不到符号。也就是说,解决这个问题并不是真的有必要,但它相当烦人
附加说明:我已经检查了许多关于CDT中索引器的其他问题,但答案并没有解决我的问题:
代码有问题还是CDT中的(已知)错误?如果我们查看
begin
inline MyIterator begin(Handle &it) { return MyIterator(it); }
我们看到它引用了一个非常量对象。这意味着您不能将临时对象传递给函数。就像直接使用do\u something()
时发生的情况。快速解决方案是添加一个采用右值引用的重载:
不过,您的代码还有其他可能的缺陷,特别是因为
dou\u something
按值返回。这意味着对do\u something
的每次调用都将返回一个单独的对象,如果do\u something
被多次调用,您将拥有具有不同数据的不同对象
还要注意的是,在C++17标准中已经弃用了。如果您需要通用类型,则应该进行专门化。所讨论的代码实际上是一致的。它使用gcc和clang的最新版本进行编译 另一个答案中的缺陷是,它没有考虑编译器对基于范围的for循环执行的重写
[stmt.ranged]p1
表示:
基于范围的for语句
for(init-statement\u opt for range declaration:for range initializer)语句
相当于
{
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\u something()
本身,而是一个隐藏(概念)变量\u range
。由于\uu range
是一个命名变量,因此它是表达式上下文中的一个左值,并且begin()
和end()
的左值引用参数将成功绑定到它
EclipseCDT在这段代码中给出了一个错误,这是一个bug,我刚刚解决了,很快就会解决。谢谢,这确实有效!但是,我仍然想知道为什么它可以正确编译(在G++5和MSVC中)。也谢谢你的额外评论@0xfull我不知道为什么它显然在GCC 5上工作,但是MSVC++对该语言有一个非标准扩展,允许将临时对象绑定到非常量引用。该代码不仅可以使用GCC 5编译,还可以使用较新版本和Clang编译。我相信它是一致的,OP在EclipseCDT中发现了一个bug。请看我的答案,我在那里解释了为什么这个代码实际上是格式良好的。
{
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
}
}
{
auto &&__range = do_something();
auto __begin = begin(__range);
auto __end = end(__range);
for ( ; __begin != __end; ++__begin ) {
auto &x = *__begin;
}
}