CRTPによる静的インターフェースクラスを用いた実装でインスタンス化せずにコンパイル時エラーを吐かせる
CRTPによる静的インタフェースクラスによって派生クラスでの該当関数の実装を強要する。
template<class _Tp> struct base{ void f()const{static_cast<_Tp>(this)->f();} }; struct derived:private base<derived>{ void f()const{} }; int main() { derived().f(); }
しかし、使わなければ実体化しないためコンパイルエラーは吐かれない。
template<class _Tp> struct base{ void f()const{static_cast<_Tp>(this)->f();} }; struct derived:private base<derived>{}; int main() { derived(); }
Qiitaに同じ問題点を挙げているエントリがある:【C++】CRTPによる静的インターフェースクラスはライブラリ実装において不適切+解決法 - Qiita
このエントリにあるようにstatic_assertを用いるのは良いと思われるが、このエントリで示されているコードはゼロオーバヘッドではない。また、指定したい関数の書式をis_sameで構成しているため直感的ではない。以下に適切な処置法を示す。
解決策
#include<type_traits> template<class _Tp,void (_Tp::*)()> struct signature_f_1{ using type=_Tp; }; template<class _Tp,class=_Tp> struct signature_f_2:std::false_type{}; template<class _Tp> struct signature_f_2<_Tp,typename signature_f_1<_Tp,&_Tp::f>::type>:std::true_type{}; template<class _Tp> constexpr bool signature_f_v=signature_f_2<_Tp>::value; template<class Derived> struct base{ virtual ~base()=default; base(){static_assert(signature_f_v<Derived>,"u must define function f");} void f(){return static_cast<Derived*>(this)->f();} };
継承先でfを作らないと
struct derived:base<derived>{}; int main() { derived(); }
怒られる。
エラー: static assertion failed: u must define function f base(){static_assert(signature_f<Derived>::value,"u must define function f");}
signature_f_1でのtemplate arguments部分で関数ポインタを書くだけなのでより直感的と言える。