为什么编译器在使用 CRTP 时看不到基 class 的方法
Why compiler does not see method of base class when using 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
}
msvc、gcc 和 clang 都拒绝此代码,它们找不到方法 Read(int x)
但是,如果我在 Crtp
中取消注释 using Iface::Read
,我的代码将成功编译。
请注意,如果我引用 Iface,我可以调用 Read(int x)
为什么会这样?
Why does this happen?
您的问题与CRTP无关。这是一个在正常的继承场景中可能会发生的名称隐藏问题。
当您调用impl.Read(24);
时,在IfaceImpl
的class范围内找不到成员函数名称Read
。然后将检查基 class Crtp
的范围,并在那里找到名称 Read
。然后名称查找停止,因此 class Iface
中的 int Read(int x)
不会被考虑用于重载解析,即使它在这里更合适。
通过 using Iface::Read;
,您将名称 Read
引入 Crtp
的 class 范围。然后可以通过重载解析正确找到和选择。
如果您通过 Iface
引用调用它,名称查找将正常工作。
或者您可以通过 impl.Iface::Read(24);
.
显式地(丑陋地)调用它
... name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.
我有如下一段代码:
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
}
msvc、gcc 和 clang 都拒绝此代码,它们找不到方法 Read(int x)
但是,如果我在 Crtp
中取消注释 using Iface::Read
,我的代码将成功编译。
请注意,如果我引用 Iface,我可以调用 Read(int x)
为什么会这样?
Why does this happen?
您的问题与CRTP无关。这是一个在正常的继承场景中可能会发生的名称隐藏问题。
当您调用impl.Read(24);
时,在IfaceImpl
的class范围内找不到成员函数名称Read
。然后将检查基 class Crtp
的范围,并在那里找到名称 Read
。然后名称查找停止,因此 class Iface
中的 int Read(int x)
不会被考虑用于重载解析,即使它在这里更合适。
通过 using Iface::Read;
,您将名称 Read
引入 Crtp
的 class 范围。然后可以通过重载解析正确找到和选择。
如果您通过 Iface
引用调用它,名称查找将正常工作。
或者您可以通过 impl.Iface::Read(24);
.
... name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.