Questo è essenzialmente un follow-up a an earlier question (non posta da me, ma io sono interessato a una risposta).chiamata metodo virtuale di modello di base dalla classe derivata template variadic
La domanda è:Perché il compilatore/linker non riescono a risolvere la chiamata alla funzione virtuale dalla classe derivata? In questo caso, la classe derivata è una classe template con parametri variadic che applica più ereditarietà rispetto alla stessa classe template più volte (una volta per ciascun tipo nei parametri variadic).
Nell'esempio concreto di seguito, la classe derivata è JobPlant
e viene chiamata da Worker
. Il richiamo del metodo astratto work()
non riesce a collegarsi, mentre si invoca i collegamenti workaround()
ed è eseguito nel modo previsto.
Questi sono i problemi nei collegamenti come mostrato da ideone:
/home/g6xLmI/ccpFAanK.o: In function `main':
prog.cpp:(.text.startup+0x8e): undefined reference to `Work<JobA>::work(JobA const&)'
prog.cpp:(.text.startup+0xc9): undefined reference to `Work<JobB>::work(JobB const&)'
prog.cpp:(.text.startup+0xff): undefined reference to `Work<JobC>::work(JobC const&)'
collect2: error: ld returned 1 exit status
Follow this link per la dimostrazione della soluzione di lavoro.
Job
è una classe base astratta, ed è associato classi derivate. Work
è una classe template astratta che esegue un lavoro. Worker
è un modello che identifica il JOB
e compie (struct
anziché class
puramente per ridurre l'ingombro sintassi):
struct Job { virtual ~Job() {} };
struct JobA : Job {};
struct JobB : Job {};
struct JobC : Job {};
template <typename JOB>
struct Work {
virtual ~Work() {}
virtual void work(const JOB &) = 0;
void workaround(const Job &job) { work(dynamic_cast<const JOB &>(job)); }
};
template <typename PLANT, typename... JOBS> struct Worker;
template <typename PLANT, typename JOB, typename... JOBS>
struct Worker<PLANT, JOB, JOBS...> {
bool operator()(PLANT *p, const Job &job) const {
if (Worker<PLANT, JOB>()(p, job)) return true;
return Worker<PLANT, JOBS...>()(p, job);
}
};
template <typename PLANT, typename JOB>
struct Worker<PLANT, JOB> {
bool operator()(PLANT *p, const Job &job) const {
if (dynamic_cast<const JOB *>(&job)) {
p->Work<JOB>::work(dynamic_cast<const JOB &>(job));
//p->Work<JOB>::workaround(job);
return true;
}
return false;
}
};
Un JobPlant
è una classe modello parametrizzato da JOBS
, che trova un Worker
per eseguire una job
. Lo JobPlant
eredita da Work
per ogni tipo di lavoro in JOBS
. MyJobPlant
è un'istanza di JobPlant
e implementa i metodi virtuali work
dalle classi associate Work
associate.
template <typename... JOBS>
struct JobPlant : Work<JOBS>... {
typedef Worker<JobPlant, JOBS...> WORKER;
bool worker(const Job &job) { return WORKER()(this, job); }
};
struct MyJobPlant : JobPlant<JobA, JobB, JobC> {
void work(const JobA &) { std::cout << "Job A." << std::endl; }
void work(const JobB &) { std::cout << "Job B." << std::endl; }
void work(const JobC &) { std::cout << "Job C." << std::endl; }
};
int main() {
JobB j;
MyJobPlant().worker(j);
}
Huh. E 'stato semplice Puoi spiegare perché chiamare 'p-> work (dynamic_cast (job))' dà un errore di ambiguità? Vedere: http://ideone.com/2vL57z –
jxh
@jxh: vedere la mia modifica :) – sth
Sostituire la 'p-> Work :: work()' seguendo il codice risolve anche il problema. Lavoro & w = * p; w.work (dynamic_cast (lavoro)); –
JVApen