5

我正在使用一个适配器来使用基于范围的 for 循环进行反向迭代。(我不知道用于此目的的升压适配器(“适配器”)。如果它是我已经下载的免费轮子,我坚信不要重新发明轮子。)

令我困惑的是为什么 VC++ 2012 不高兴,除非我在下面的代码中使用尾随返回类型:

#include <string>
#include <iostream>

template<class Fwd>
struct Reverser {
    const Fwd &fwd;
    Reverser<Fwd>(const Fwd &fwd_): fwd(fwd_) {}
    auto begin() -> decltype(fwd.rbegin()) const { return fwd.rbegin(); } 
    auto end() ->   decltype(fwd.rend())   const { return fwd.rend(); } 
};

template<class Fwd>
Reverser<Fwd> reverse(const Fwd &fwd) { return Reverser<Fwd>(fwd); }

int main() {
    using namespace std;
    const string str = ".dlrow olleH";
    for(char c: reverse(str)) cout << c;
    cout << endl;
}

当我尝试以下操作时,我得到了错误,“错误 C2100:非法间接”和“错误 C2228:'.rbegin' 的左侧必须有类/结构/联合”。我错过了什么?

template<class Fwd>
struct Reverser {
    const Fwd &fwd;
    Reverser<Fwd>(const Fwd &fwd_): fwd(fwd_) {}
    decltype(fwd.rbegin()) begin() const { return fwd.rbegin(); } 
    decltype(fwd.rend())   end() const { return fwd.rend(); } 
};

更新:根据关于“this”指针的讨论,我尝试了另一种方法。看妈,不是这个!它编译得很好。我确实相信,无论对错,VC++ 都没有意识到这一点。

template<class Fwd>
struct Reverser {
    const Fwd &fwd;
    Reverser<Fwd>(const Fwd &fwd_): fwd(fwd_) {}
    decltype(((const Fwd*)0)->rbegin()) begin() const { return fwd.rbegin(); } 
    decltype(((const Fwd*)0)->rend())   end()   const { return fwd.rend(); } 

};

更新 2:提交给 MS:https ://connect.microsoft.com/VisualStudio/feedback/details/765455/vc-2012-compiler-refuses-decltype-return-spec-for-member-function

更新 3:这个问题自 VC++ 2015 起已修复。谢谢,微软人。

4

1 回答 1

5

来自 OP 的注意事项:VC++ 有问题。VC++ 2015 正确接受代码。

我最初的回答是,标准中不允许 VC++ 拒绝的代码实际上是错误的:正如 Johannes Schaub 指出的那样是允许的:在 5.1 [expr.prim.general] 第 12 段中,它描述了一个id-expression表示非可以使用静态数据成员或非静态成员函数。特别是,最后一个项目符号指出:

如果该 id-expression 表示非静态数据成员并且它出现在未计算的操作数中。

中的表达式decltype(expr)是一个未计算的操作数。此外,9.3.1 [class.mfct.non-static] 第 3 段解释了this隐式添加到表达式的情况:

当不属于类成员访问语法 (5.2.5) 并且不用于形成指向成员 (5.3.1) 的指针的 id 表达式 (5.1) 用于类 X 的成员中时,可以使用 (5.1.1),如果名称查找 (3.4) 将 id 表达式中的名称解析为某个类 C 的非静态非类型成员,并且如果 id 表达式可能被评估或 C 是X 或 X 的基类,使用 (*this) (9.3.2) 作为 . 操作员。

所讨论的上下文不是“可能评估的”,也没有涉及任何依据。因此,this没有添加,也不必在范围内。综合起来,这意味着声明

decltype(fwd.rbegin()) begin() const;

应该是合法的。似乎使用

decltype(static_cast<Reverser<Fwd> const*>(0)->fwd.rbegin()) begin() const;

在编译器未正确实现的情况下是一种解决方法。

于 2012-09-29T21:48:08.453 回答