Chamando o método virtual do modelo base da classe de modelo variadic derivada

Este é essencialmente um acompanhamento parauma pergunta anterior (não colocado por mim, mas estou interessado em uma resposta).

A questão é: Por que o compilador / vinculador falha ao resolver a chamada para a função virtual da classe derivada? Nesse caso, a classe derivada é uma classe de modelo com parâmetros variadicos que aplica herança múltipla à mesma classe de modelo várias vezes (uma vez para cada tipo nos parâmetros variadicos).

No exemplo concreto abaixo, a classe derivada éJobPlante está sendo chamado deWorker. Invocando o resumowork() O método falha ao vincular, enquanto invocaworkaround() vincula e executa da maneira esperada.

Essas são as falhas do link, conforme mostrado porideona:

/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 link para demonstração do trabalho de solução alternativa.

Job é uma classe base abstrata e associou classes derivadas.Work é uma classe de modelo abstrata que executa um trabalho.Worker é um modelo que identifica oJOB e executa (struct ao invés declass puramente para reduzir a desordem de sintaxe):

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 é uma classe de modelo parametrizada porJOBS, que encontra umWorker para executar umjob. oJobPlant herda deWork para cada tipo de trabalhoJOBS. MyJobPlant é uma instância deJobPlante implementa o virtualwork métodos do associadoWork aulas abstratas.

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

questionAnswers(1)

yourAnswerToTheQuestion