CRTP to avoid virtual member function overhead
在CRTP中,为了避免动态多态性,为了避免虚拟成员函数的开销并强制使用特定的接口,提出了以下解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | template <class Derived> struct base { void foo() { static_cast<Derived *>(this)->foo(); }; }; struct my_type : base<my_type> { void foo() {}; // required to compile. < Don't see why }; struct your_type : base<your_type> { void foo() {}; // required to compile. < Don't see why }; |
但是,派生类似乎不需要编译定义,因为它继承了一个定义(代码编译良好,而不定义my_type::foo)。实际上,如果提供了函数,则在使用派生类时不会调用基函数。
所以问题是,以下代码替换是否可以接受(和标准?):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | template <class Derived> struct base { void foo() { // Generate a meaningful error if called (void)sizeof( Derived::foo_IS_MISSING ); }; }; struct my_type : base<my_type> { void foo() {}; // required to compile. }; struct your_type : base<your_type> { void foo() {}; // required to compile. }; int main() { my_type my_obj; my_obj.foo(); // will fail if foo missing in derived class } |
据我所知,这个模式的全部要点是,您可以简单地将参数传递为
请注意,您不是像使用纯虚拟函数那样"强制"一个接口,而是提供一个接口。因为所有的问题都是在编译时解决的,"强制"并不是一个很强的要求。
但是,派生类似乎不需要编译定义,因为它继承了一个定义(代码编译良好,而不定义my_type::foo)。
C++是懒惰的:如果你不实际使用它,它就不会尝试创建Base[MyOyType >::FoE()。但是,如果您尝试使用它,那么它将被创建,如果失败,编译错误将流动。但在您的情况下,可以很好地通知base
1 2 3 4 5 6 7 8 9 10 11 12 13 | template <class Derived> struct base { void foo() { static_cast<Derived *>(this)->foo(); }; }; struct my_type : base<my_type> {}; void func() { my_type m; static_cast<base<my_type>& >(m).foo(); } |
编译得很好。当编译器static_cast(this)->foo(),它将尝试查找在我的_类型中可访问的foo()。还有一个:它被称为base
在替换代码中,不能"多态"地调用
不,想象一下以下情况:
1 2 3 4 5 6 7 | template <typename T> void bar(base<T> obj) { obj.foo(); } base<my_type> my_obj; bar(my_obj); |
基地的foo将被调用,而不是我的类型的…
这样做,你就会得到你的错误信息:
1 2 3 4 5 6 7 | template <class Derived> struct base { void foo() { sizeof(Derived::foo); static_cast<Derived *>(this)->foo(); }; }; |
但我必须承认,我不确定这在GCC之外的编译器中是如何工作的,只在GCC中测试。