I have the following piece of code:
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
}
Both msvc, gcc and clang reject this code, they cannot find method Read(int x)
However if I uncomment using Iface::Read
in Crtp
my code compiles successfully.
Note that if I take a reference to Iface I can call Read(int x)
Why does this happen?
Why does this happen?
Your problem has nothing to do with CRTP. It's a name hiding issue that may happen in a normal inheritance scenario.
When you call impl.Read(24);
, the member function name Read
can't be found at the class scope of IfaceImpl
. Then the scope of base class Crtp
will be examined, and the name Read
found there. Then name lookup stops, so int Read(int x)
in the further base class Iface
won't be considered for overload resolution, even though it is more appropriate here.
By using Iface::Read;
you're introducing the name Read
into the class scope of Crtp
. Then it could be found and selected by overload resolution correctly.
And if you call it via Iface
reference, the name lookup will work well.
Or you can call it explicitly (and ugly) by impl.Iface::Read(24);
.
See Unqualified name lookup:
... 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With