2012-02-23 14 views
7

Visual Studio 2010およびそれ以前のバージョンに付属するstd::vectorの実装はよく知られています。resizeメソッドのシグネチャは次のとおりです(C++ 03準拠) :std :: vectorの自己完結型STL互換実装

void resize(size_type new_size, value_type value); 

代わりに長いC++ 11の前(GCCのSTL又はSTLportのような)他のSTL実装の大部分で使用されていますC++ 11準拠の署名:

void resize(size_type new_size, const value_type& value); 

最初の変種の問題は、ある状況では

struct __declspec(align(64)) S { ... }; 
std::vector<S> v; // error C2719: '_Val': formal parameter with __declspec(align('64')) won't be aligned 

これは離れstd::vectorの異なる実装を使用してから満足な回避策とwellknown問題である:ション、それはvalue_typeアライメント仕様を有する場合、コンパイルに失敗します。

私は整列のための選択のコンテナとしての私のプロジェクトにドロップすることができMITスタイルのライセンスstd::vectorのよく書かれた、十分にテストされた、自己完結型とSTL互換の実装を探していますタイプ。

私はそれをSTLportまたはgccのSTLから抽出することを検討しましたが、完全に標準に準拠していますが、それらは両方とも大した重要ではありません。

(私だけpush_backclearcapacitysizereserveresizeswapと配列のインデックスをサポートするstd::vectorの合理的なサブセットの実装と完全に幸せになる。)

任意のアイデア?

+0

'.resize()'メソッドによって 'std :: vector v;'宣言が失敗する仕組みがわかりません。クラステンプレートをインスタンス化しても、そのメソッドはインスタンス化されず、使用されたものだけがインスタンス化されます。 (この場合、デフォルトのctorとdtor)。 – MSalters

+0

私は、解析中にエラーが発生したと思います...ここでは、本当にコンパイラ固有の問題について話しています。 –

答えて

8

連中は、Visual StudioのSTLに実装されているstd::vectorに「過度に整列タイプ」(as Stephan T. Lavavej call them)を格納する問題のために素敵な回避策を発見したように見えます。私は、固有で実装について

#include <vector> 

template <typename T> 
struct wrapper : public T 
{ 
    wrapper() {} 
    wrapper(const T& rhs) : T(rhs) {} 
}; 

struct __declspec(align(64)) S 
{ 
    float x, y, z, w; 
}; 

int main() 
{ 
    std::vector< wrapper<S> > v; // OK, no C2719 error 
    return 0; 
} 

彼らの実装が不要な複雑(ソースherehereを確認してください)が、主なアイデアは薄いラッパーでstd::vectorに入るタイプをカプセル化することであると思われます彼らが作る必要があるなぜ彼らはEigen::aligned_allocator_indirection

  • を必要とする理由私はかなり

    • を理解していない認めなければなりませんn個のEIGEN_WORKAROUND_MSVC_STL_SUPPORTにおける算術演算の種類の例外、
    • 彼らはEigen::workaround_msvc_stl_supportに、これらすべてのコンストラクタと演算子を定義する必要がある理由、
    • または彼らはEigen::aligned_allocator_indirectionアロケータのためのstd::vectorのその部分特殊でresizeを再定義する必要がある理由...

    手がかりを歓迎します。ポイントは、このトリックは(私が言うことができる限り)完璧に動作し、それに何か間違っているとは思えません。

  • 1

    最も簡単な(そして最良のimho)オプションは、正しいことを行うvectorインターフェイスの拡張機能として、無料の機能を提供することです。あなたは、しかし、ちょうどドロップしたい場合

    template<class T, class Alloc> 
    void resize(std::vector<T, Alloc>& v, 
        typename std::vector<T, Alloc>::size_type new_size) 
    { 
        v.resize(new_size); // simply forward 
    } 
    

    :また、単一の引数バージョン

    #include <vector> 
    
    template<class T, class Alloc> 
    void resize(std::vector<T, Alloc>& v, 
        typename std::vector<T, Alloc>::size_type new_size, T const& val) 
    { 
        if (v.size() < new_size) 
         v.insert(v.end(), new_size - v.size(), val); 
        else if (new_size < v.size()) 
         v.erase(v.begin() + new_size, v.end()); 
    } 
    

    と一貫性のために:あなたはresizeを実装するために必要な機能はすべてstd::vectorのパブリックインターフェイスから利用できます新しいベクトルで、決して自由やメンバ関数を心配し、別のオプションは、単にstd::vectorをサブクラス化することです。

    #include <vector> 
    #include <memory> 
    
    template<class T, class Alloc = std::allocator<T>> 
    class myvector 
        : public std::vector<T, Alloc> 
    { 
        typedef std::vector<T, Alloc> base; 
    public: 
        typedef typename base::size_type size_type; 
    
        void resize(size_type new_size){ 
        base::resize(new_size); 
        } 
    
        void resize(size_type new_size, T const& val){ 
        if (this->size() < new_size) 
         this->insert(this->end(), new_size - this->size(), val); 
        else if (new_size < this->size()) 
         this->erase(this->begin() + new_size, this->end()); 
        } 
    }; 
    

    私はresizeの単一引数バージョンも提供しました。これは、2つの引数バージョンがすべてのベースクラスバージョンを隠すためです。また、基本クラスstd::vectorに依存しているので、すべてのメンバー関数の呼び出しにはthis->という接頭辞を付ける必要があります。 Eigenライブラリーの背後にある

    +0

    +1、サブクラス化が境界線であることに気付くでしょう... –

    +1

    'std :: vector'をサブクラス化することは私の最初のアプローチの1つでした。残念ながら、最後に' std :: vector'がまだインスタンス化されているため。 –

    +1

    @FrançoisBeaune:ああ、それは比較的残念です。 :/ 'std :: vector'のバージョンをコメントアウトするか、単純に署名を修正してください。 :P FWIW、VS11はこの問題を解決しません。 – Xeo

    関連する問題