質問

親プロジェクト全体で使用される多くの汎用コード スニペットを含むサブプロジェクト「commonUtils」があります。私が見たそのような興味深いものの 1 つは:-

/*********************************************************************
If T is polymorphic, the compiler is required to evaluate the typeid 
stuff at runtime, and answer will be true.  If T is non-polymorphic, 
the compiler is required to evaluate the typeid stuff at compile time, 
whence answer will remain false
*********************************************************************/
template <class T> 
bool isPolymorphic() { 
   bool answer=false; 
   typeid(answer=true,T()); 
   return answer; 
}

私はコメントを信じて、それはプロジェクト全体で使用されていないものの、非常に興味深いテンプレートであると考えました。興味本位でこんな感じで使ってみました...

class PolyBase {
public:
   virtual ~PolyBase(){}
};

class NPolyBase {
public:
   ~NPolyBase(){}
};


if (isPolymorphic<PolyBase>())
  std::cout<<"PolyBase = Polymorphic\n";
if (isPolymorphic<NPolyBase>())
  std::cout<<"NPolyBase = Also Polymorphic\n";

しかし、それらはいずれも true を返しません。MSVC 2005 は警告を出しませんが、Comeau は typeid 式は効果がないと警告しています。C++ 標準のセクション 5.2.8 には、コメントに記載されているようなことは何も記載されていません。typeid は、非多態性型の場合はコンパイル時に評価され、多態性型の場合は実行時に評価されます。

1) つまり、コメントは誤解を招く/明らかに間違っていると思います。それとも、このコードの作成者はかなり上級の C++ プログラマーなので、何かが欠けているのでしょうか?

2) OTOH、何らかの手法を使用してクラスがポリモーフィック(少なくとも1つの仮想関数を持つ)かどうかをテストできるかどうか疑問に思っています。

3) クラスがポリモーフィックであるかどうかを知りたいのはどのような場合ですか?当てずっぽう;を使用してクラスの開始アドレスを取得するには dynamic_cast<void*>(T) (として dynamic_cast 多態性クラスでのみ機能します)。

ご意見お待ちしております。

前もって感謝します、

役に立ちましたか?

解決

typeid を使用して型がポリモーフィックであることを確認する方法を想像することもできません。typeid はどの型でも機能するため、それが正しいと主張するために使用することさえできません。Boostには実装があります ここ. 。なぜそれが必要なのかというと、私が知っているケースの 1 つは Boost.Serialization ライブラリです。非ポリモーフィック型を保存する場合は、そのまま保存できます。ポリモーフィックな型を保存する場合は、typeid を使用して動的型を取得し、その型のシリアル化メソッドを呼び出す必要があります (テーブルで検索します)。

アップデート:どうやら私は実際には間違っているようです。次のバリエーションを考えてみましょう。

template <class T> 
bool isPolymorphic() { 
    bool answer=false;
    T *t = new T();
    typeid(answer=true,*t); 
    delete t;
    return answer; 
}

これは実際には、名前が示すとおり、元のコード スニペットのコメントどおりに機能します。typeid 内の式は、「多態性クラス型の左辺値を指定しない」場合には評価されません (std 3.2/2)。したがって、上記の場合、T がポリモーフィックでない場合、typeid 式は評価されません。T が多態性の場合、 *t は確かに多態性型の左辺値であるため、式全体を評価する必要があります。

さて、元の例はまだ間違っています:-)。使用しました T(), 、 ない *t. 。そして T() 作成する 右辺値 (標準 3.10/6)。したがって、依然として「多態性クラスの左辺値」ではない式が生成されます。

それはかなり興味深いトリックです。一方、実際の値はある程度制限されています。boost::is_polymorphic はコンパイル時の定数を提供しますが、これは実行時の値を提供するため、ポリモーフィック型と非ポリモーフィック型に対して異なるコードをインスタンス化することはできません。 。

他のヒント



class PolyBase {
public:   
    virtual ~PolyBase(){}
};

class NPolyBase {
public:
    ~NPolyBase(){}
};

template<class T>
struct IsPolymorphic
{
    struct Derived : T {
        virtual ~Derived();
    };
    enum  { value = sizeof(Derived)==sizeof(T) };
};


void ff()
{
    std::cout << IsPolymorphic<PolyBase >::value << std::endl;
    std::cout << IsPolymorphic<NPolyBase>::value << std::endl;
}

C ++ 11は、これが<type_traits>としてstd::is_polymorphicヘッダーに利用できるようになりました。それは、このように使用することができます:

struct PolyBase {
  virtual ~PolyBase() {}
};

struct NPolyBase { 
  ~NPolyBase() {}
};

if (std::is_polymorphic<PolyBase>::value)
  std::cout << "PolyBase = Polymorphic\n";
if (std::is_polymorphic<NPolyBase>::value)
  std::cout << "NPolyBase = Also Polymorphic\n";

この印刷物は、単に "ポリ塩基多型性=" ます。

次のような事実を利用できます。

  1. dynamic_cast 引数が多態性クラスでない場合、コンパイル時に失敗します。SFINAEでも使えるように。
  2. dynamic_cast<void*> のアドレスを返す有効なキャストです。 完了 多態性オブジェクト。

したがって、C++11 では次のようになります。

#include <iostream>
#include <type_traits>

template<class T>
auto is_polymorphic2_test(T* p) -> decltype(dynamic_cast<void*>(p), std::true_type{});

template<class T>
auto is_polymorphic2_test(...) -> std::false_type;

template<class T>
using is_polymorphic2 = decltype(is_polymorphic2_test<T>(static_cast<T*>(0)));

struct A {};
struct B { virtual ~B(); };

int main() {
    std::cout << is_polymorphic2<A>::value << '\n'; // Outputs 0.
    std::cout << is_polymorphic2<B>::value << '\n'; // Outputs 1.
}

私はここで少し混乱している、と私は欠けているものを説明するこの回答にいくつかのコメントを取得するために期待しています。

きっとあなたはクラスが多型であるかどうかを知りたい場合は、あなたがしなければならないすべては、それがdynamic_castをサポートしているかどうかを尋ねるそれは右ではないですね。

template<class T, class> struct is_polymorphic_impl   : false_type {};
template<class T> struct is_polymorphic_impl
    <T, decltype(dynamic_cast<void*>(declval<T*>()))> : true_type {};

template<class T> struct is_polymorphic :
    is_polymorphic_impl<remove_cv_t<T>, void*> {};

誰もがこの実装の不備を指摘することはできますか?私は、これは、<のhref = "http://www.boost.org/doc/libs/1_64_0/libs/type_traits/doc/html/boost_typetraits、1、または過去のある時点で一つとなっている必要がありますが存在しなければならないと想像します/intrinsics.html」RELは= 『nofollowをnoreferrerは移植『C ++言語で実装することができない』>ブーストドキュメントには、そのis_polymorphicを主張し続ける。』

しかし、「移植性」、右、イタチの言葉のようなものでしょうか?おそらく彼らは、ちょうどMSVC式-SFINAEをサポートしていないかをほのめかしている、またはそのような組み込みC ++などの一部の方言はdynamic_castをサポートしていません。彼らは、「C ++言語」と言うときおそらく彼らは、意味「C ++言語の最小共通分母のサブセットを。」しかし、私は多分、彼らは彼らの言うことを意味し、そのしつこい疑いを持っているのIよの何かが欠けている1。を

(左辺値ではない右辺値を使用するように、後でその答えによって修正された)OPでtypeidアプローチも細かいようだが、もちろんそれは、constexprのではないですし、それが実際に超高価かもしれませんTを構築する必要があります。それが何らかの理由で動作しない場合を除きしたがって、このdynamic_castアプローチは...良さそうです。思考?

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top