web-dev-qa-db-ja.com

C ++でtypedefを使用する必要があるのはいつですか?

私の長年のC++(MFC)プログラミングでは、typedefを使用する必要性を感じたことはなかったので、何に使用されているのかわかりません。どこで使用すればよいですか? typedefの使用が推奨される実際の状況はありますか?または、これは本当にC固有のキーワードですか?

65
djeidot

テンプレートのメタプログラミング

typedefnecessary多くの テンプレートメタプログラミング タスク-クラスが「コンパイルtypedefは、結果型を取得するための「コンパイル時型値」として使用されます。例えば。ポインター型をその基本型に変換するための単純なメタ関数を考えてみましょう。

template<typename T>
struct strip_pointer_from;

template<typename T>
struct strip_pointer_from<T*> {   // Partial specialisation for pointer types
    typedef T type;
};

例:型式strip_pointer_from<double*>::typedoubleと評価されます。テンプレートのメタプログラミングは、ライブラリ開発以外では一般的に使用されないことに注意してください。

関数ポインタ型の簡素化

typedefhelpfulで、複雑な関数ポインター型に短くて明確なエイリアスを与えるためのものです。

typedef int (*my_callback_function_type)(int, double, std::string);

void RegisterCallback(my_callback_function_type fn) {
    ...
}
85
j_random_hacker

Bjarneの本では、整数のサイズが異なるシステム間の移植性の問題にtypedefを使用して対処できると述べています。 (これは言い換えです)

sizeof(int)が4のマシンでは、次のことができます。

_typedef int int32;
_

次に、コードのすべての場所で_int32_を使用します。 sizeof(int)が2であるC++の実装に移行する場合、typdefを変更するだけです。

_typedef long int32;
_

プログラムは引き続き新しい実装で動作します。

33
Jason Punyon

関数ポインターで使用

Typedefを使用して関数ポインター宣言を非表示にする

void (*p[10]) (void (*)() );

Pが「voidを返す関数への10個のポインターの配列であり、voidを返し、引数をとらない別の関数へのポインターを取得する」ことを知ることができるプログラマーはほとんどいません。面倒な構文はほとんど判読できません。ただし、typedef宣言を使用することで大幅に簡素化できます。まず、次のように「voidを返し、引数を取らない関数へのポインタ」のtypedefを宣言します。

  typedef void (*pfv)();

次に、以前に宣言したtypedefに基づいて、「voidを返し、pfvを受け取る関数へのポインター」の別のtypedefを宣言します。

 typedef void (*pf_taking_pfv) (pfv);

扱いにくい「voidを返し、pfvを取得する関数へのポインター」の同義語としてpf_taking_pfv typedefを作成したので、このような10個のポインターの配列を宣言するのは簡単です。

  pf_taking_pfv p[10];

from

22
yesraaj

言われたことのいくつかの例を提供するために:STLコンテナー。

 typedef std::map<int,Froboz> tFrobozMap;
 tFrobozMap frobozzes; 
 ...
 for(tFrobozMap::iterator it=frobozzes.begin(); it!=map.end(); ++it)
 {
     ...
 }

次のようなtypedefを使用することも珍しくありません

typedef tFrobozMap::iterator tFrobozMapIter;
typedef tFrobozMap::const_iterator tFrobozMapCIter;

別の例:共有ポインターの使用:

class Froboz;
typedef boost::shared_ptr<Froboz> FrobozPtr;

[更新]コメント通り-それらをどこに置くか?

最後の例-shared_ptrを使用するのは簡単です:本当のヘッダー素材です-少なくともフォワードヘッダーです。とにかくshared_ptrの前方宣言が必要です。その宣言された利点の1つは、前方宣言で安全に使用できることです。

別の言い方をすれば、shared_ptrがある場合は、shared_ptrを介してのみ型を使用する必要があるため、宣言を分離してもあまり意味がありません。

(はい、xyzfwd.hは苦痛です。ホットスポットでのみ使用します-ホットスポットを特定するのは難しいことを知っています。C++コンパイル+リンクモデルを非難します...)

私は通常、コンテナ変数が宣言されている場所で使用するコンテナタイプ定義-例えば実際のコンテナインスタンスがクラスメンバである場合、ローカルvarの場合はローカル、クラスメンバとして。実際のコンテナタイプが実装の詳細である場合、これはうまく機能します-追加の依存関係を引き起こしません。

それらがparticularインターフェースの一部になる場合、使用されるインターフェースとともに宣言されます。

// FrobozMangler.h
#include "Froboz.h"
typedef std::map<int, Froboz> tFrobozMap;
void Mangle(tFrobozMap const & frobozzes); 

タイプが異なるインターフェイス間のバインディング要素である場合、つまり、複数のヘッダーで同じタイプが必要な場合、問題が生じます。いくつかの解決策:

  • 含まれるタイプと一緒に宣言します(このタイプに頻繁に使用されるコンテナに適しています)
  • それらを別のヘッダーに移動します
  • 別のヘッダーに移動し、実際のコンテナーが実装の詳細であるデータクラスにします

後者の2つはそれほど優れていないことに同意します。トラブルに直面したときにのみ(積極的にではなく)使用します。

17
peterchen

typedefは多くの状況で役立ちます。

基本的に、型のエイリアスを作成できます。タイプを変更する必要がある場合、または変更する必要がある場合、残りのコードは変更されない可能性があります(もちろん、コードによって異なります)。たとえば、C++ベクトルを反復処理するとします。

vector<int> v;

...

for(vector<int>::const_iterator i = v->begin(); i != v.end(); i++) {

// Stuff here

}

将来的には、リストでベクトルを変更することを考えるかもしれません。なぜなら、あなたがそれに対してしなければならない操作のタイプだからです。 typedefを使用しないと、コード内のすべてのベクトルの発生を変更する必要があります。しかし、次のようなものを書く場合:

typedef vector<int> my_vect;

my_vect v;

...

for(my_vect::const_iterator i = v->begin(); i != v.end(); i++) {

// Stuff here

}

これで、1行のコードを変更するだけです(つまり、「typedef vector<int> my_vect "から" typedef list<int> my_vect ")そしてすべてが機能します。

typedefは、書き込みが非常に長い(そして読みにくい)複雑なデータ構造がある場合にも時間を節約します

5
Emiliano

Typedefを使用する理由の1つは、何かのタイプが変更される可能性がある場合です。たとえば、現時点では、一部のデータセットのインデックス化には16ビットintが適しているとしましょう。予見できる将来のために、65535個未満のアイテムがあり、スペースの制約が大きいか、キャッシュのパフォーマンスが優れている必要があるからです。ただし、65535を超えるアイテムを持つデータセットでプログラムを使用する必要がある場合は、より広い整数に簡単に切り替えられるようにする必要があります。 typedefを使用すると、これを1か所で変更するだけで済みます。

5
dsimcha

typedefは、複雑な型のエイリアスを持つだけでなく、型を文書化するための自然な場所を提供します。私は時々文書化の目的でそれを使用します。

バイト配列を使用することもあります。現在、バイトの配列は多くのことを意味する可能性があります。 typedefは、バイト配列を「hash32」または「fileContent」として定義してコードを読みやすくするのに便利です。

4
Ztyx

Typedefを使用するもう1つのユースケースは、一種のContainer Independent code(ただし正確ではありません!)を有効にする場合です。

クラスがあるとしましょう:

Class CustomerList{

public:
    //some function
private:
    typedef list<Customer> CustomerContainer;
    typedef CustomerContainer::iterator Cciterator;
};

上記のコードは、typedefを使用して内部コンテナー実装をカプセル化します。将来、リストコンテナーをベクターまたはデックに変更する必要がある場合でも、CustomerListクラスのユーザーは正確なコンテナー実装を心配する必要はありません。

したがって、typedefはカプセル化され、コンテナに依存しないコードを書くのにいくらか役立ちます

2
Imran Al Noor

Typedefの実際の使用:

  • 複雑なテンプレート型にわかりやすいエイリアスを提供する
  • 関数ポインター型にわかりやすいエイリアスを提供する
  • タイプにローカルラベルを提供します。例:

    template<class _T> class A
    {
        typedef _T T;
    };
    
    template<class _T> class B
    {
        void doStuff( _T::T _value );
    };
    
2
moonshadow

ソースが明確になるか、読みやすくなるたびに。

ジェネリック/テンプレートには、C#で一種のtypedefを使用します。 「NodeMapping」は、多くの「Dictionary <string、XmlNode>」を読んだり使用したり理解したりするのに適しています。私見では。そのため、テンプレートにそれをお勧めします。

0
Leonidas

Typedefを使用すると、クラスの柔軟性が高まります。プログラムでデータ型を変更する場合、複数の場所を変更する必要はなく、1回だけ変更する必要があります。

typedef <datatype example  int or double> value_type

value_typeの代わりにnay名を付けることができますが、通常はvalue_typeが標準名です。

したがって、次のようにtypedefを使用できます。

value_type i=0;     //same as a int or double i=0; 
0
sneha