Вызов виртуального метода базового шаблона из производного класса шаблона variadic

По сути, это продолжениепредыдущий вопрос (не задано мной, но я заинтересован в ответе).

Вопрос в том: Почему компилятор / компоновщик не может разрешить вызов виртуальной функции из производного класса? В этом случае производный класс - это шаблонный класс с переменными параметрами, который несколько раз применяет множественное наследование к одному и тому же классу шаблона (по одному разу для каждого типа в параметрах переменной).

В приведенном ниже конкретном примере производный классJobPlantи это вызывается изWorker, Вызывая рефератwork() метод не в состоянии связать, вызываяworkaround() ссылки и выполняется ожидаемым образом.

Это ошибки связи, как показано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

Перейдите по этой ссылке для демонстрации работы обходного пути.

Job является абстрактным базовым классом, и он имеет связанные производные классы.Work это абстрактный шаблон класса, который выполняет работу.Worker это шаблон, который идентифицируетJOB и выполняет это (struct вместоclass чисто для уменьшения синтаксического беспорядка):

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 класс шаблона, параметризованныйJOBS, который находитWorker выполнитьjob,JobPlant наследует отWork для каждого типа работы вJOBS. MyJobPlant является примеромJobPlantи реализует виртуальныйwork методы из связанных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);
}

Ответы на вопрос(1)

Ваш ответ на вопрос