Martin Ueding Martin Ueding - 8 days ago 7
C++ Question

Inherited member function seems undeclared, what is going on?

I would like to compile a C++ software which gives me a couple of compilation
errors. This error is about a member function that cannot be resolved.

This question should contain everything needed to answer it. However, if that
really was the case, I should have found the answer by now. So please feel free
to browse the source
code
.
All code in this question is not mine but licensed under the GPLv2.

The system I compile on is an IBM PowerPC 740 running Red Hat Enterprise Server
6.8. Using modules, I have enabled Clang 3.7. Everything gets cross-compiled
for IBM PowerPC A2 chips, it is an IBM BlueGene/Q supercomputer. Those things
should be taken care by my compilation
script

that sets the many

configure
and
CXXFLAGS
needed.

The compilation error that I currently get with the my current state (commit
fee0a02
) is this one:

bfmcommqmp.C:183:5: error: use of undeclared identifier 'gather'
gather(result_cb, psi, dag);
^


The offending line is in this method definition in
bfmcommqmp.C
:

168 template <class Float>
169 void bfmcommQMP<Float>::comm_start(int result_cb, Fermion_t psi, int dag) {
170 // gather the faces. Routines here are threaded.
171 // All threads cooperate in gathering.
172
173 // if ( this->isBoss() && (me == 0)) {
174 // this->Error("comm_start checking heap\n"); fflush(stdout);
175 // mcheck_check_all();
176 // this->Error("comm_start mcheck_all");fflush(stdout);
177 // }
178
179 int me = this->thread_barrier();
180
181 this->thread_barrier();
182
183 gather(result_cb, psi, dag);
184
185 this->thread_barrier();
186 if (me == 0) {
187 comm_qmp_start(psi);
188 }
189 this->thread_barrier();
190
191 return;
192 }


This is of course part of the
bfmcommQMP
class. Looking at the associated
header file,
bfmcommqmp.h
, one finds this class declaration:

8 template <class Float>
9 class bfmcommQMP : public bfmbase<Float> {
10 public:
11 // QMP thingy-me-bob's
12 QMP_msghandle_t multi_handle[2];
13
14 QMP_msgmem_t send_ops_msgmem_t[8];
15 QMP_msgmem_t recv_ops_msgmem_t[8];
16
17 QMP_msghandle_t send_multi_handle;
18 QMP_msghandle_t send_handles[8];
19
20 QMP_msghandle_t recv_handles[8];
21 QMP_msghandle_t all_handles;
22
23 Float *simd_rbuf[8];
24 Float *receive_area;
25
26 int num_op;
27
28 virtual bool isBoss();
29
30 virtual void recv_init(void);
31 virtual void recv_end(void);
32
33 virtual void comm_init(void);
34 virtual void comm_end(void);
35 virtual void comm(int result_cb, Fermion_t psi, int dag);
36 virtual void comm_start(int result_cb, Fermion_t psi, int dag);
37 virtual void comm_qmp_start(Fermion_t psi);
38 virtual void comm_qmp_complete(void);
39 virtual void comm_merge(void);
40 virtual void comm_complete(int result_cb, Fermion_t psi);
41 virtual void comm_gsum(double &val);
42 virtual void comm_gsum(double *val, int N);
43 };


It inherits from
bfmbase
. Jumping to the file
bfm.h
which is included in
bfmcommqmp.h
, we find the class definition, which contains two
gather

methods:

133 template <class Float>
134 class bfmbase : public bfmarg, public ThreadModel {
135 public:

282 void gather(int result_cb, Fermion_t psi, int dag);
283 void gather(int mu, int result_cb, Fermion_t psi, int dag);

1018 };


From my understanding, the class
bfmcommQMP
should have inherited the
non-virtual function
gather
from
bfmbase
. Apparently that is not the case,
otherwise Clang would not complain about that.

What am I missing here? Why is the function
gather
not available inside the
bfmcommQMP::comm_start
member function?

Answer

The problem is that your derived class is a dependent name. You need to qualify the call to gather() in the base class with this->gather() instead, otherwise the compiler does not resolve gather() from the base class. To simplify,

template<class T> struct Base
{
    void f();
};

template<class T> struct Derived: Base<T> // dependent name
{
    void foo()
    {
        this->f(); // won't compile without this->
    }
};

An alternative is to do

using Base::f;

in the derived Derived::foo() or qualify the call like

Base::f();

Related: Why do I have to access template base class members through the this pointer?

Comments