Reputation: 153
I'm getting a C++ compiler error that I don't understand and haven't been able to find a fix or an explanation for. Here is a code snippet demonstrating the problem.
#include <iostream>
template<class T>
class A {
public:
A(int n) {data = new T[n]; }
const T &operator()(int i) const {return data[i];}
protected:
T *data;
};
template<class T>
class B : public A<T> {
public:
B(int n) : A<T>(n) {}
T &operator()(int i) {return this->data[i]; }
//const T &operator()(int i) const {return this->data[i];} // fixes problem
};
template<class T, int N>
class C : public B<T> {
public:
C() : B<T>(N) {}
private:
};
template<class T>
void doOp(const T &v) {
std::cout << v(0) << std::endl;
}
void templateTest()
{
C<double, 3> c;
c(0) = 5;
std::cout << c(0) << std::endl;
doOp(c);
}
If I un-comment the line in class B, the code compiles and executes correctly but I don't understand why defining this operator function in class B is any different from the definition in class A.
Thanks for the help.
Bill
Upvotes: 1
Views: 183
Reputation: 126432
The problem is that doOp()
is invoking a non-const
member function through a reference to const
.
If you uncomment the commented line, a viable const
member function will be found, and overload resolution will pick that version of the call operator.
Without uncommenting that line, the inherited version of the call operator is not found because it is being hidden by the overloaded call operator in the subclass.
To illustrate the problem of name hiding with a simpler example, consider the following program:
struct X
{
void foo() { }
};
struct Y : X
{
void foo(int) { }
};
int main()
{
Y y;
y.foo(42); // OK
y.foo(); // ERROR! Name hiding...
}
The compiler here won't be able to resolve the call to y.foo()
, because X::foo()
is being hidden by Y::foo()
here.
To fix the problem, you could add a using
declaration in Y
:
struct X
{
void foo() { }
};
struct Y : X
{
using X::foo;
// ^^^^^^^^^^^^^
void foo(int) { }
};
int main()
{
Y y;
y.foo(42); // OK
y.foo(); // OK
}
Now both function calls are correctly resolved. In your program, you could add a similar using
declaration for operator ()
of the base class:
template<class T>
class B : public A<T> {
public:
B(int n) : A<T>(n) {}
T &operator()(int i) {return this->data[i]; }
using A<T>::operator();
// ^^^^^^^^^^^^^^^^^^^^^^^
};
Upvotes: 2