san*_*san 4 c++ templates crtp
我想要更好地了解CRTP.到目前为止,我的理解是它允许人们编写如下的函数.
template <class T>
void foo(Base<T> x ) { x.do_stuff() }
Run Code Online (Sandbox Code Playgroud)
现在,根据x
传递给函数的实际编译时派生对象,foo()
它将执行不同的操作.
但是,我可以Derived
从非虚拟但被覆盖的派生类Base
和掩盖/阴影它.因此,当使用CRTP完全正确时,更确切地说是最简单的非平凡示例,它显示了CRTP优于阴影/屏蔽的优势.do_stuff()
Derived::do_stuff
CRTP的目的是能够在没有虚拟的情况下获取派生对象的类型.如果你这样做
struct B { void foo() const; }
struct D : B { void foo() const; }
void bar(const B& x) { x.foo(); }
Run Code Online (Sandbox Code Playgroud)
然后bar
调用B::foo
而不是D::foo
在传递D
对象时,因为foo
它不是虚函数.如果要D::foo
调用,则需要虚函数或CRTP.
使用最简单的CRTP:
template <typename>
struct B { void foo() const; }
struct D : B<D> { void foo() const; }
template <typename T>
void bar(const B<T>& x)
{
static_cast<const T&>(x).foo();
}
Run Code Online (Sandbox Code Playgroud)
这就要求D::foo()
当你传递给bar
一个D
对象.
另一种CRTP技巧,无论如何强制D
提供实现foo
,都是
template <typename T>
struct B
{
void foo() const { static_cast<const T*>(this)->foo_impl(); }
// default implementation if needed
// void foo_impl() const { ... }
};
struct D : B<D> { void foo_impl() const { ... } };
template <typename T>
void bar(const B<T>& x) { x.foo(); }
Run Code Online (Sandbox Code Playgroud)
但是你仍然需要一个模板参数B
(以便foo
正确调度),因此需要一个模板bar
函数.
此外,如果你不做CRTP,你最好有一个虚拟析构函数,这可能会为轻量级类增加不必要的开销,这些类本意味着完全内联.使用CRTP,您只需编写一个受保护的析构函数(私有析构函数+ friend T
在C++ 0x中).