Ale*_*xey 5 c++ inheritance crtp
我有以下代码:
struct Iface
{
virtual int Read() = 0;
int Read(int x) {
return Read() + x;
}
};
template <typename Impl>
struct Crtp : public Iface
{
virtual int Read() {
return static_cast<Impl&>(*this).ReadImpl();
}
//using Iface::Read;
};
struct IfaceImpl : public Crtp<IfaceImpl>
{
int ReadImpl() {
return 42;
}
};
int main()
{
IfaceImpl impl;
impl.Read(24); // compilation error
Iface& iface = impl;
iface.Read(24); // always compiles successfully
}
Run Code Online (Sandbox Code Playgroud)
msvc,gcc和clang都拒绝这个代码,他们找不到方法 Read(int x)
但是如果我using Iface::Read在Crtp我的代码中取消注释成功编译.
请注意,如果我参考Iface,我可以打电话 Read(int x)
为什么会这样?
为什么会这样?
您的问题与CRTP无关.这是在正常继承方案中可能发生的名称隐藏问题.
调用时impl.Read(24);,Read无法在类的范围内找到成员函数名IfaceImpl.然后Crtp将检查基类的范围,并在Read那里找到名称.然后名称查找停止,因此int Read(int x)在进一步的基类中Iface不会考虑重载解析,即使它在这里更合适.
通过using Iface::Read;你将名称Read引入到类的范围内Crtp.然后可以通过正确的重载分辨率找到并选择它.
如果你通过Iface引用调用它,名称查找将很好.
或者你可以通过明确(和丑陋)调用它impl.Iface::Read(24);.
请参阅非限定名称查找:
... name lookup检查范围如下所述,直到它找到至少一个任何类型的声明,此时查找停止并且不再检查其他范围.