ura*_*nix 21 c++ virtual-functions crtp pure-virtual
请考虑以下标准CRTP示例:
#include <iostream>
template<class Derived>
struct Base {
void f() { static_cast<Derived *>(this)->f(); }
void g() { static_cast<Derived *>(this)->g(); }
};
struct Foo : public Base<Foo> {
void f() { std::cout << 42 << std::endl; }
};
int main() {
Foo foo;
foo.f(); // just OK
foo.g(); // this will stack overflow and segfault
}
Run Code Online (Sandbox Code Playgroud)
如果这是常规虚拟继承,我可以将虚拟f和g方法标记为纯粹
struct Base {
virtual void f() = 0;
virtual void g() = 0;
};
Run Code Online (Sandbox Code Playgroud)
并获得关于Foo抽象的编译时错误.但是CRTP没有提供这样的保护.我可以以某种方式实现它吗?运行时检查也是可以接受的.我想过将this->f指针与比较static_cast<Derived *>(this)->f,但没有设法让它工作.
Hol*_*olt 24
您可以在编译时断言成员函数的两个指针是不同的,例如:
template<class Derived>
struct Base {
void g() {
static_assert(&Derived::g != &Base<Derived>::g,
"Derived classes must implement g().");
static_cast<Derived *>(this)->g();
}
};
Run Code Online (Sandbox Code Playgroud)
Oli*_*liv 12
你可以使用这个解决方案,你可以拥有纯粹的"非虚拟抽象"功能,并尽可能地映射到CRTP这个H. Sutter的推荐:
template<class Derived>
struct Base
{
void f(){static_cast<Derived*>(this)->do_f();}
void g(){static_cast<Derived*>(this)->do_g();}
private:
//Derived must implement do_f
void do_f()=delete;
//do_g as a default implementation
void do_g(){}
};
struct derived
:Base<derived>
{
friend struct Base<derived>;
private:
void do_f(){}
};
Run Code Online (Sandbox Code Playgroud)
Joh*_*itb 12
这是另一种可能性:
#include <iostream>
template<class Derived>
struct Base {
auto f() { return static_cast<Derived *>(this)->f(); }
auto g() { return static_cast<Derived *>(this)->g(); }
};
struct Foo : public Base<Foo> {
void f() { std::cout << 42 << std::endl; }
};
int main() {
Foo foo;
foo.f(); // just OK
foo.g(); // this will not compile
}
Run Code Online (Sandbox Code Playgroud)
对于GCC,它给出了一个非常明确的错误消息("错误:使用'auto Base :: g()[使用Derived = Foo]',然后扣除'auto'"),而对于Clang,它提供的可读性略低无限递归模板实例化Base<Foo>::g,g实例化自身但最终以错误结束.