Llamada al método virtual de plantilla base a partir de la clase de plantilla variable derivada

Esto es esencialmente un seguimiento deuna pregunta anterior (No planteado por mí, pero estoy interesado en una respuesta).

La pregunta es: ¿Por qué el compilador / enlazador no resuelve la llamada a la función virtual desde la clase derivada? En este caso, la clase derivada es una clase de plantilla con parámetros variables que aplica la herencia múltiple contra la misma clase de plantilla varias veces (una vez para cada tipo en los parámetros variables).

En el siguiente ejemplo concreto, la clase derivada esJobPlant, y se llama desdeWorker. Invocando el resumenwork() el método no se puede vincular al invocarworkaround() enlaza y ejecuta de la manera esperada.

Estas son las fallas del enlace como se muestra enideona:

/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

Siga este enlace para la demostración de la solución alternativa de trabajo.

Job es una clase base abstracta y tiene clases derivadas asociadas.Work es una clase de plantilla abstracta que realiza un trabajo.Worker es una plantilla que identifica elJOB y lo realiza (struct en lugar declass puramente para reducir el desorden de sintaxis):

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;
    }
};

A JobPlant es una clase de plantilla parametrizada porJOBS, que encuentra unWorker para realizar unjob. losJobPlant hereda deWork para cada tipo de trabajo enJOBS. MyJobPlant es una instancia deJobPlante implementa el virtualwork métodos de la asociadaWork clases abstractas

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);
}

Respuestas a la pregunta(1)

Su respuesta a la pregunta