5

範囲ベースのforループを使用して逆方向に反復するためのアダプターを試してみました。(私はその目的のためのブーストアダプター(「アダプター」)について知りませんでした。私は、それがすでにダウンロードしたフリーホイールである場合、ホイールを再発明しないことを大いに信じています。)

私を困惑させるのは、次のコードで末尾のreturn-typeを使用しない限り、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」の左側にはclass / struct/unionが必要です」というエラーが発生しました。私は何が欠けていますか?

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 ++が拒否したコードが標準で許可されていないという私の最初の答えは、実際には間違っていました。JohannesSchaubが指摘したように、許可されています。5.1[expr.prim.general]段落12で、id式が非静的データメンバーまたは非静的メンバー関数を使用できます。特に、最後の箇条書きは次のように述べています。

そのid式が非静的データメンバーを示し、未評価のオペランドに表示される場合。

の式decltype(expr)は未評価のオペランドです。さらに、9.3.1 [class.mfct.non-static]段落3はthis、式に暗黙的に追加される状況を説明しています。

クラスメンバーアクセス構文(5.2.5)の一部ではなく、メンバー(5.3.1)へのポインターを形成するために使用されないid-expression(5.1)が、このコンテキストでクラスXのメンバーで使用される場合名前ルックアップ(3.4)がid-expression内の名前をあるクラスCの非静的非型メンバーに解決し、id-expressionが潜在的に評価されるか、CがXまたはXの基本クラスであるid-expressionは、の左側にある後置式として(* this)(9.3.2)を使用して、クラスメンバーアクセス式(5.2.5)に変換されます。オペレーター。

問題のコンテキストは「潜在的に評価」されておらず、関連するベースはありません。したがって、thisは追加されず、スコープ内にある必要はありません。まとめると、これは宣言が

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

合法である必要があります。使用しているようです

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

コンパイラが正しく実装されていない場合の回避策です。

于 2012-09-29T21:48:08.453 に答える