web-dev-qa-db-ja.com

テンプレート化されたtypedef?

CとC++のガベージコレクターであるlibgcを使用しています。 STLコンテナーのガベージコレクションを可能にするには、gc_allocatorを使用する必要があります。

書く代わりに

std::vector<MyType> 

人は書く必要があります

std::vector<MyType,gc_allocator<MyType> >

次のようなものを定義する方法はありますか

template<class T> typedef std::vector<T,gc_allocator<T> > gc_vector<T>;

しばらく前に確認したところ、不可能だとわかりました。しかし、私は間違っていたか、別の方法があるかもしれません。

この方法でマップを定義することは特に不愉快です。

std::map<Key,Val> 

なる

std::map<Key,Val, std::less<Key>, gc_allocator< std::pair<const Key, Val> > >

編集:マクロの使用を試みた後、次のコードがそれを壊すことがわかりました:

#define gc_vector(T) std::vector<T, gc_allocator<T> >
typedef gc_vector( std::pair< int, float > ) MyVector;

テンプレート化された型定義内のコンマは、マクロ引数セパレーターとして解釈されます。

したがって、内部クラス/構造体が最良の解決策のようです。

これは、C++ 0Xでの実行方法の例です

// standard vector using my allocator
template<class T>
using gc_vector = std::vector<T, gc_allocator<T> >;

// allocates elements using My_alloc
gc_vector <double> fib = { 1, 2, 3, 5, 8, 13 };

// verbose and fib are of the same type
vector<int, gc_vector <int>> verbose = fib; 
38
chmike

usingを使用して、C++ 11テンプレートタイプのエイリアスを使用できます。このような

template <typename T>
using gc_vector = std::vector<T, gc_allocator<T>>;

注:私はこれが古い質問であることを知っていますが、非常に多くの賛成票があり、検索結果に表示されるため、更新された回答に値すると思いました。

77
Snps

"テンプレート化されたtypedef"を使用することはできませんが、内部型で便利なクラス/構造体を使用できます。

template<typename T>
struct TypeHelper{
    typedef std::vector<T,gc_allocator<T> > Vector;
};

そしてあなたのコードで使用します

TypeHelper<MyType>::Vector v;
TypeHelper<MyType>::Vector::iterator it;

そして、マップについても同様です:

template<typename K,typename V>
struct MapHelper{
    typedef std::map<K, V, gc_allocator<K,V> > Map;
};

編集-@Vijay:別の可能な回避策があるかどうかはわかりません。それが私が行う方法です。マクロはもっとコンパクトな表記を与えるかもしれませんが、個人的には私はそれが好きではありません:

#define GCVECTOR(T) std::vector<T,gc_allocator<T> >

編集-@chmike:TypeHelperソリューションしないでくださいはコンストラクタを再定義する必要があることに注意してください!

34
Paolo Tedesco

あなたは公に継承することができます:

template<class T>
class gc_vector<T> : public std::vector<T, gc_allocator<T> >
{
    public:
    // You'll have to redeclare all std::vector's constructors here so that
    // they just pass arguments to corresponding constructors of std::vector
};

これはあなたの問題を完全に解決します。派生型は、基本型を使用できる場所ならどこでも使用でき、適切なコンパイラを使用した場合の実装オーバーヘッドはありません。

Std :: vectorに非仮想デストラクタがあるという事実は、基本クラス変数へのポインターを介して派生クラス変数を削除しようとすると、C++標準に従って未定義の動作を引き起こす可能性があります。

現実の世界では、この特定のケースではこれは問題になりません。派生クラスには基本クラスと比較して新しく追加されたものがないため、派生クラスのデストラクタは基本クラスのデストラクタを呼び出すだけです。パラノイアを進め、とにかく慎重に移植してください。

このクラス変数をヒープに割り当てなかった場合(そして、スタックに他のクラスのメンバーとしてベクトル変数を割り当てるのが一般的である場合)、非仮想デストラクタの問題は影響しません。

8
sharptooth

コンパイラを限界までプッシュしたい場合は、MACROを使用して実行できます。 Javaの「Future」クラスと「Callable」クラスに相当するC++を実装するときにそれを行いました。私たちのライブラリは参照カウントオブジェクトを使用しているため、「Reference <T>」自体が「T」が「ReferencedObject」から派生するテンプレートクラスです。

1. Create your template Classes. Mine are:

    template<typename T>
    class Callable {
    private:

    public:
        virtual T Call() = 0;
    };

    template<typename T> CountedFuture : public ReferencedObject {
    private:
       Callable<T>* theTask;
       T            theResult;

    public:
       T Get() { 
          // Run task if necessary ...
          if(task) {
             theResult = theTask->Call();
             delete theTask;
          }
          return theResult;
       }
    };

2. In the application code I'm using references, so I define the macro:

   #define Future(T) Reference<CountedFuture<T>>

これの美点は、マクロが「テンプレートのtypedef」に必要な機能を正確に実行することです。欠点は、型パラメーターに「<>」を使用できず、型の推論がないことです。 。

3. I can now use the Macro wherever I would use a template, like in functions:

   Future(char*) DoSomething() { ... }
   bool          TestSomething(Future(std::string) f) { .... }
1
Zack Yezek