2013-03-13 7 views
6

ベクトル計算を行うためのC++コードをいくつか書いていました。これは、std::arrayインスタンスの周りの薄いラッパーに必須です。非会員のbegin()関数をオーバーロードして、イテレータをバッキング配列の先頭に戻したいと考えました。これを行うには、autoの戻り値の型と後続の戻り値の型を持つ単純なfriend関数を書きました。これは、呼び出しをメンバー変数に転送したばかりのdecltypeを使用しています。Visual StudioとG ++のDecltype関数とfriend関数

それはコンパイルされず、私は理由を理解できませんでした。私は小規模な例を取り上げて、次のコードがG ++ 4.7ではコンパイルされているが、最新のVisual Studio 2012 Professionalではコンパイルされていないことを発見しました。

#include <iostream> 
#include <array> 

template <typename T, size_t size> 
class MyClass { 

private: 
    std::array<T, size> elts; 

public: 
    friend auto begin(MyClass &a) -> decltype (std::begin(a.elts)) { 
     return std::begin(a.elts); 
    } 

}; 

int main(void) { 
    MyClass<int, 8> instance; 
    auto it = begin(instance); 
    std::cout << *it << std::endl; 
    return 0; 
} 

eltsのプライベート宣言がbegin()関数の宣言の前に来た場合は奇妙なことが唯一のG ++でこのコードをコンパイルしました。

いずれにしても、どのコンパイラがここにありますか? Visual StudioまたはG ++?

編集:VS2012を与えたことを、コンパイルエラーがerror C2228: left of '.elts' must have class/struct/union

答えて

7

クラステンプレートMyClassの定義は、あなたが表現std::begin(a.elts)を使う時点で完全なものではありませんでしたので、私はVCが文句を言う理由があると思います。不完全な型のoperator .は使用できません。

いずれにせよ、あなたは以下を使用して、その回避できます

#include <iostream> 
#include <array> 

template <typename T, size_t size> 
class MyClass 
{ 
    // ... 

    friend typename std::array<T, size>::iterator begin(MyClass &a) 
    //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    { 
     return std::begin(a.elts); 
    } 
}; 
+0

をなぜ 'typename'はここでは必要でしょうか? –

+2

@duiu: 'std :: array 'は従属型であるためです。 – ildjarn

関連する問題