C ++での「typeid」と「typeof」


158

C ++ typeidtypeofC ++の違いは何ですか。これが私が知っていることです:

  • typeidドキュメントに記載されている TYPE_INFO C ++ヘッダファイルに定義されているのTypeInfo

  • typeofCのGCC拡張およびC ++ Boostライブラリで定義されています。

また、ここに、私が作成したテストコードテストがあります。ここでは、typeid期待した結果を返さないことがわかりました。どうして?

main.cpp

#include <iostream>  
#include <typeinfo>  //for 'typeid' to work  

class Person {  
    public:
    // ... Person members ...  
    virtual ~Person() {}  
};  

class Employee : public Person {  
    // ... Employee members ...  
};  

int main () {  
    Person person;  
    Employee employee;  
    Person *ptr = &employee;  
    int t = 3;  

    std::cout << typeid(t).name() << std::endl;  
    std::cout << typeid(person).name() << std::endl;   // Person (statically known at compile-time)  
    std::cout << typeid(employee).name() << std::endl; // Employee (statically known at compile-time)  
    std::cout << typeid(ptr).name() << std::endl;      // Person * (statically known at compile-time)  
    std::cout << typeid(*ptr).name() << std::endl;     // Employee (looked up dynamically at run-time  
                                                       // because it is the dereference of a pointer
                                                       // to a polymorphic class)  
 }  

出力:

bash-3.2$ g++ -Wall main.cpp -o main  
bash-3.2$ ./main   
i  
6Person  
8Employee  
P6Person  
8Employee

8
コードが正しい型名を出力しないと思いますか?よさそうだ。が返す実際の文字列name()は実装定義です。これは、有効なC ++の識別子名だけである必要はありません何かユニークタイプを識別します。実装がコンパイラの一般的な名前のマ​​ングリング方式を使用しているようです。
ロブ・ケネディ

ロブありがとう!en.wikipedia.org/wiki/Typeidで見たタイプ名とまったく同じものを期待していました。ここで名前変換は何ができますか?
ティム

私のようなtypeidが初めての場合:vtableをオンにするには、基本型に仮想関数が必要です。そうしないと、最後の行で基本型が出力されます。
jw_

回答:


198

C ++言語にはのようなものはありませんtypeof。コンパイラ固有の拡張機能を確認している必要があります。GCCについて話している場合typeof、C ++ 11にはキーワードを介して同様の機能がありdecltypeます。繰り返しますが、C ++にはそのようなtypeofキーワードはありません。

typeid実行時に型識別情報を返すC ++言語の演算子です。基本的に、type_info他のtype_infoオブジェクトと同等のオブジェクトを返します。

返されるtype_infoオブジェクトの唯一の定義されたプロパティは、同等および非同等であることに注意してください。つまり、type_info異なるタイプを説明するオブジェクトは非同等を比較type_infoし、同じタイプを説明するオブジェクトは同等に比較する必要があります。それ以外はすべて実装定義です。さまざまな「名前」を返すメソッドは、人間が読めるものを返すことは保証されていません。

また、上記はおそらく、(標準では明示的には言及されていないようですが)typeid同じタイプへの連続したアプリケーションが異なるtype_infoオブジェクトを返す可能性があることを意味します(もちろん、等しいものを比較する必要があります)。


1
C ++ 11があるので、これは更新が必要ではdecltypeないでしょうか?一般的なポリシーは何なのかわかりませんが、質問にタグC++が付いているので、最新の標準を参照していると思います。質問のタグを付け直すC++03ことも、オプションです。仕事でpreC ++ 11を使用しなければならないため、個人的にかなり混乱することがあります。
idclev 463035818

11
参考までにdecltype、の代わりにはなりませんtypeoftypeof型に対しても機能しますが、decltype機能しません。例えば、typeof(int)あるintながらdecltype(int)誤差です。
Shahbaz

1
type_info異なるタイプを記述するオブジェクトは、等しくないものを比較するものとします」。実際には、これは保証されていません。不等式演算子はC ++ 20で削除され、(等しくないと思われる)異なる型を比較して異なる型に依存することを防いでいます。しかし、考えてみると、不平等が安全でなければ、平等は安全ではありません。
インディアナカーニック

50

2つの主な違いは次のとおりです。

  • typeofはコンパイル時の構文であり、コンパイル時に定義された型を返します
  • typeidは実行時の構成要素であるため、値の実行時のタイプに関する情報を提供します。

リファレンスのタイプ:http ://www.delorie.com/gnu/docs/gcc/gcc_36.html

typeidリファレンス:https : //en.wikipedia.org/wiki/Typeid


JaredPar、ありがとう!返信を読んだ後、更新された投稿にいくつか新しい質問があります。たとえば、それらの戻り値がさまざまな目的で使用されることが真実である場合など:typeofの戻り値は、変数を定義できるtypeキーワードとして使用されますが、typeidの戻り値は使用できませんか?
ティム

26

typeidは実行時に動作し、オブジェクトのランタイムタイプを記述するオブジェクトを返すことができます。これは、RTTI(ランタイムタイプ情報)をクラスに格納するために、仮想メソッドを持つクラスのオブジェクトへのポインタでなければなりません。また、実行時の型情報を持つクラスへのポインタが指定されていない場合は、式のコンパイル時の型または型名を指定できます。

typeofGNU拡張機能であり、コンパイル時に任意の式のタイプを提供します。これは、たとえば、複数の型で使用される可能性のあるマクロで一時変数を宣言する場合に役立ちます。C ++では、通常、代わりにテンプレートを使用します。


5
私の知る限りtypeid、仮想メソッドでオブジェクトに評価される式だけでなく、任意の式を受け入れます。さらに、typeid式だけでなくタイプも受け入れます。あなたが言うtypeid(5)typeid(std::string)、またはあなたが望むなら。
ロブ・ケネディ

1
私はそれを明確にするために私の答えを明確にしました。typeid 可能な場合はランタイム型情報を返すことができますが、それ以外の場合はコンパイル時型情報を提供します。
ブライアンキャンベル

ブライアンとロブ、ありがとう!返信を読んだ後、更新された投稿にいくつか新しい質問があります。
ティム

22

追加の質問に答える:

typeidの次のテストコードは、正しいタイプ名を出力しません。どうしましたか?

何も問題はありません。表示されるのは、型名の文字列表現です。標準C ++は、コンパイラーにクラスの正確な名前を出力させることはありません。適切なものを決定するのはインプリメンター(コンパイラーベンダー)の責任です。つまり、名前はコンパイラ次第です。


これらは2つの異なるツールです。typeof式のタイプを返しますが、これは標準ではありません。C ++ 0xにはdecltype、同じことをAFAIKで行うと呼ばれるものがあります。

decltype(0xdeedbeef) number = 0; // number is of type int!
decltype(someArray[0]) element = someArray[0];

一方、typeidは多相型で使用されます。たとえば、次のようにcat導出するとしますanimal

animal* a = new cat; // animal has to have at least one virtual function
...
if( typeid(*a) == typeid(cat) )
{
    // the object is of type cat! but the pointer is base pointer.
}

アラック、ありがとう!私はいくつかの新しい質問で投稿を更新しました。なるべくご覧ください。
ティム

4

typeidは、要求されたときに、実行時のデータのタイプを提供します。Typedefは、後で説明するように新しい型を定義するコンパイル時の構造です。C ++にはtypeofはありません。出力は次のように表示されます(内接コメントとして表示):

std::cout << typeid(t).name() << std::endl;  // i
std::cout << typeid(person).name() << std::endl;   // 6Person
std::cout << typeid(employee).name() << std::endl; // 8Employee
std::cout << typeid(ptr).name() << std::endl;      // P6Person
std::cout << typeid(*ptr).name() << std::endl;     //8Employee

3

Boost demangleを使用して、見栄えの良い名前を実現できます。

#include <boost/units/detail/utility.hpp>

そして何かのような

To_main_msg_evt ev("Failed to initialize cards in " + boost::units::detail::demangle(typeid(*_IO_card.get()).name()) + ".\n", true, this);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.