または少なくとも私はそうだと思います。 ベースで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>()
でコンパイル。
現在の状態では、このコードをコンパイルする必要はありません。 'SD1'の定義には明らかな問題があります。 CRTPクラス 'SBase'は' SDerived'の 'foo'メンバ関数を呼び出そうとしています。しかし、それがテンプレートパラメータとして 'SD1'でインスタンス化されるとき、このメンバ関数は存在しません。だからこのプログラムは悪いです。私はgccやclangがエラーなしでこのプログラムをコンパイルするとは思わない。これが実際にランタイムクラッシュをコンパイルして生成するコードであることを確認できますか? –
@ChrisBeck 'SBase :: foo()'が呼び出されると、実際には 'SDerived *'ポインタで 'foo'を呼び出そうとします。この場合、 'SDerived'は' SD1'です。そして 'SD1'は呼び出すことができる' foo'メンバーを持っています。それは継承されたメンバ 'SBase :: foo'です。 –
aschepler
@aschepler:ありがとう、それはコードの作成者にとっては非常に不幸です。 –