2017-07-20 7 views
-1

または少なくとも私はそうだと思います。 ベースでvirtualコードをせずに次のコードCRTPなぜメンバー検索ランタイムですか?

#include <iostream> 
#include <memory> 

struct BaseBase { 
    virtual void foo() = 0; 
    virtual ~BaseBase(){} 
}; 

template <typename Derived> 
struct Base : BaseBase{ 
    void foo() override{ 
     static_cast<Derived*>(this)->foo(); 
    } 
}; 

struct D1 : Base<D1> {}; 
struct Unrelated {}; 

// no runtime polymorphism 
template <typename SDerived> 
struct SBase{ 
    void foo() { 
     static_cast<SDerived*>(this)->foo(); 
    } 
}; 

struct SD1 : SBase<SD1> {}; 


template <typename T, typename ...Args> 
void doFoo(Args&&... args){ 
    T* t = new T(std::forward<Args>(args)...); 
    t->foo(); 
} 

int main(){ 
    doFoo<Unrelated>(); //compile time error, foo not found in unrelated 
    doFoo<SD1>(); //runtime crash 
    doFoo<D1>(); //runtime crash 
    return 0; 
} 

私は、コンパイラがベースでvirtualと、doFooではなく、両方のケースでは、コンパイル時にfooの存在を確認するために十分いいだろう期待していた、とを考慮してください実行時に正常にコンパイルされますが、クラッシュします。

これはなぜですか?

編集:doFoo<Unrelated>()コメントアウトコンパイルと打ち鳴らす設定

clang version 4.0.1 (tags/RELEASE_401/final) 
Target: x86_64-unknown-linux-gnu 

とg ++セットアップ

gcc version 7.1.1 20170630 (GCC) 

はコメントアウトdoFoo<Unrelated>()でコンパイル。

+1

現在の状態では、このコードをコンパイルする必要はありません。 'SD1'の定義には明らかな問題があります。 CRTPクラス 'SBase'は' SDerived'の 'foo'メンバ関数を呼び出そうとしています。しかし、それがテンプレートパラメータとして 'SD1'でインスタンス化されるとき、このメンバ関数は存在しません。だからこのプログラムは悪いです。私はgccやclangがエラーなしでこのプログラムをコンパイルするとは思わない。これが実際にランタイムクラッシュをコンパイルして生成するコードであることを確認できますか? –

+1

@ChrisBeck 'SBase :: foo()'が呼び出されると、実際には 'SDerived *'ポインタで 'foo'を呼び出そうとします。この場合、 'SDerived'は' SD1'です。そして 'SD1'は呼び出すことができる' foo'メンバーを持っています。それは継承されたメンバ 'SBase :: foo'です。 – aschepler

+1

@aschepler:ありがとう、それはコードの作成者にとっては非常に不幸です。 –

答えて

3

これは両方のクラスにfooという関数があるためです。これは、各クラスの基本クラスに存在します。

しかし、その機能はすべて呼び出し自体であり、最終的にはスタックのオーバーフローが発生します。

+0

どのように私はこれを逃した、コンパイラは、親構造体で表示されるので、両方のクラスのfooを見る... 2時には朝のコード:) – arynaq

関連する問題