Jest to w zasadzie kontynuacja an earlier question (nie jestem przeze mnie postawiony, ale jestem zainteresowany odpowiedzią).Wywołanie wirtualnej metody szablonu bazowego z wyprowadzonej szablonu szablonu warstwy zastępczej
Pytanie brzmi:Dlaczego kompilator/linker nie rozwiąże wywołanie funkcji wirtualnych z klasy pochodnej? W tym przypadku klasa pochodna jest klasą szablonów z parametrami variadic, która stosuje wielokrotne dziedziczenie względem tej samej klasy szablonów wiele razy (jeden raz dla każdego typu w parametrach variadic).
W konkretnym przykładzie poniżej klasa pochodna to JobPlant
i jest wywoływana od Worker
. Wywołanie abstrakcyjnej metody work()
nie łączy się, wywołując linki workaround()
i wykonuje w oczekiwany sposób.
Są awarie łącza, jak pokazano przez 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 do demonstracji obejście roboczego.
Job
jest abstrakcyjną klasą podstawową i ma powiązane klasy pochodne. Work
to klasa abstrakcyjnych szablonów, która wykonuje zadanie. Worker
jest szablon, który identyfikuje JOB
i wykonuje go (struct
zamiast class
wyłącznie w celu zmniejszenia bałaganu składni):
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;
}
};
JobPlant
jest klasa szablon parametryzowane przez JOBS
, że znajdzie Worker
wykonać job
. JobPlant
dziedziczy po Work
dla każdego rodzaju pracy w JOBS
. MyJobPlant
jest instancją JobPlant
i implementuje metody wirtualne work
z powiązanych klas abstrakcyjnych Work
.
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. To było proste. Czy możesz wyjaśnić, dlaczego wywołanie 'p-> pracy (dynamic_cast (zadanie)) powoduje błąd niejednoznaczności? Zobacz: http://ideone.com/2vL57z –
jxh
@jxh: Zobacz moją edycję :) – sth
Zastąpienie "p-> Work :: work()" przez następujący kod rozwiązuje również problem. Praca & w = * p; w.work (dynamic_cast (zadanie)); –
JVApen