c ++:type_infoタイプを区別します
質問
私は、コンパイラが実装に多くの自由を持っていることを知っています std::type_info
関数の動作。
私はそれを使用してオブジェクトタイプを比較することを考えているので、私はそれを確信したいです:
std::type_info::name
2つの異なるタイプの2つの異なる文字列を返す必要があります。std::type_info::before
それを言わなければなりませんType1
は 前Type2
排他的またはType2
は 前Type1
.// like this: typeid(T1).before( typeid(T2) ) != typeid(T2).before( typeid(T1) )
同じテンプレートクラスの2つの異なる専門化は、異なるタイプと見なされます。
2つの異なる
typedef
- 同じタイプのイニションは同じタイプです。
そして最後に:
以来
std::type_info
コピー可能ではありません、どうすれば保存できますかtype_info
sどこか(例:astd::map
)?それが持っている唯一の方法std::type_info
常にどこか(例:スタックまたは静的/グローバル変数)を常に割り当て、ポインターを使用しますか?どれだけ速いですか
operator==
,operator!=
とbefore
最も一般的なコンパイラで?値を比較するだけであると思います。そして、どれだけ速いかtypeid
?クラスがあります
A
とともにvirtual bool operator==( const A& ) const
. 。以来A
多くのサブクラスがあります(コンパイル時には不明です)、あらゆるサブクラスにその仮想演算子を過負荷しますB
こちらです:virtual bool operator==( const A &other ) const { if( typeid(*this) != typeid(other) ) return false; // bool B::operator==( const B &other ) const // is defined for any class B return operator==( static_cast<B&>( other ) ); }
これは、そのようなオペレーターを実装するための許容可能な(および標準的な)方法ですか?
解決
ドキュメントを少し見た後、私はそれを言うでしょう:
std :: type_info :: nameは常に2つの異なるタイプに対して2つの異なる文字列を返します。そうしないと、コンパイラがタイプを解決しながら自分自身を失ったことを意味します。
参照は次のように語っています。「タイプが照合順序でRHSのタイプに先行する場合、trueを返す前に。照合順序は、特定の実装によって保持されている内部順序であり、必ずしも継承関係や命令の宣言に関連しているわけではありません。」したがって、照合順序で同じランクを持っているタイプはないという保証があります。
テンプレートクラスの各インスタンス化は異なるタイプです。専門化例外はありません。
私はあなたが何を意味するのか本当に理解していません。あなたが持っているようなものを意味する場合
typedef foo bar;
2つの独立したコンピレーションユニットで、そのバーは両方で同じで、そのように機能します。あなたが意味するならtypedef foo bar; typedef int bar;
, 、機能しません(FooがINTである場合を除きます)。
あなたの他の質問について:
- 参照をSTD :: TYPE_INFOに保存する必要があります。
- パフォーマンスについてはまったく考えていません。比較演算子は、タイプの複雑さにもかかわらず一定の時間があると思います。コードで使用されているさまざまなタイプの数に応じて、前に線形の複雑さが必要です。
- これは本当に奇妙な私見です。オーバーロードする必要があります
operator==
仮想にしてオーバーライドする代わりに。
他のヒント
標準18.5.1(class type_info):
クラスTYPE_INFOは、実装によって生成されたタイプ情報について説明します。このクラスのオブジェクトは、ポインターをタイプの名前に効果的に保存し、2つのタイプを平等または照合順序で比較するのに適したエンコード値を保存します。 タイプの名前、エンコードルール、および照合シーケンスはすべて不特定であり、プログラム間で異なる場合があります.
私の理解から:
- この保証はありません
std:type_info::name
. 。標準はそれだけを述べていますname
戻り値 実装定義のNTB, 、そして、適合の実装は、すべてのタイプに対して同じ文字列を非常にうまく返すことができると思います。 - 私は知りません、そして、この点で標準は明確ではないので、私はそのような行動に頼らないでしょう。
- それは私にとって明確な「はい」であるべきです
- それは私にとって明確な「はい」であるべきです
2番目の質問について:
- いいえ、保存することはできません
type_info
. 。 Andrei Alexandrescuは提案しますTypeInfo
その中のラッパー 最新のC ++デザイン 本。ご了承ください によって返されたオブジェクトtypeid
静的ストレージがあります したがって、オブジェクトの寿命を心配することなく、ポインターを安全に保存できます - 私はあなたがそれを想定できると信じています
type_info
比較は非常に効率的です(実際には比較することはあまりありません)。
このように保存できます。
class my_type_info
{
public:
my_type_info(const std::type_info& info) : info_(&info){}
std::type_info get() const { return *info_;}
private:
const std::type_info* info_;
};
編集:
C ++標準5.2.8。
TypeID式の結果は、静的タイプconst std :: type_infoのlvalueです。
つまり、このように使用できます。
my_type_info(typeid(my_type));
TypeID関数はlvalueを返します(一時的ではありません)。したがって、返されたtype_infoのアドレスは常に有効です。
質問1と2の現在の回答は完全に正しいものであり、それらは本質的にType_Infoクラスの詳細にすぎません。これらの回答を繰り返すことはありません。
質問3と4の場合、C ++のタイプであるものと、それらが名前とどのように関連するかを理解することが重要です。まず第一に、事前定義されたタイプがたくさんあり、それらには次の名前があります。 int, float, double
. 。次に、構築されたタイプがいくつかあります いいえ 自分の名前を持っている: const int, int*, const int*, int* const
. 。関数タイプがあります int (int)
および関数ポインタータイプ int (*)(int)
.
名前を無名のタイプに与えることは時々便利です。 typedef
. 。例えば、 typedef int* pint
また typedef int (*pf)(int);
. 。これにより、新しいタイプではなく名前が紹介されます。
次はユーザー定義のタイプです:構造体、クラス、ユニオン。名前を付ける良い慣習がありますが、必須ではありません。 Typedefにそのような名前を追加しないでください、あなたは直接それをすることができます: struct Foo { };
それ以外の typedef struct {} Foo;
. 。ヘッダーにクラスの定義があることが一般的です。ヘッダーは、複数の翻訳ユニットで終了します。つまり、クラスが複数回定義されていることを意味します。これはまだ同じタイプであるため、クラスメンバーの定義を変更するためにマクロでトリックをプレイすることは許可されていません。
テンプレートクラスはです いいえ タイプ、それはタイプのレシピです。テンプレートの引数が異なるタイプ(または値)である場合、単一のクラステンプレートの2つのインスタンス化は異なるタイプです。これは再帰的に機能します:与えられます template <typename T> struct Foo{};
, Foo<Foo<int> >
と同じタイプです Foo<Foo<Bar> >
場合にのみ Bar
タイプの別名です int
.
Type_Infoは実装が定義されているため、私は本当に依存しません。ただし、G ++とMSVCを使用した私の経験に基づいて、1,3と4の仮定は、#2についてはあまり確信がありません。
このような別の方法を使用できない理由はありますか?
template<typename T, typename U>
struct is_same { static bool const result = false; };
template<typename T>
struct is_same<T, T> { static bool const result = true; };
template<typename S, typename T>
bool IsSame(const S& s, const T& t) { return is_same<S,T>::result; }