【发布时间】:2014-12-10 00:46:39
【问题描述】:
这基本上是an earlier question 的后续行动(不是我提出的,但我对答案很感兴趣)。
问题是: 为什么编译器/链接器无法解析派生类对虚函数的调用?在此在这种情况下,派生类是具有可变参数的模板类,它对同一个模板类多次应用多重继承(可变参数中的每种类型一次)。
在下面的具体示例中,派生类是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
Follow this link 演示解决方法的工作原理。
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;
}
};
JobPlant 是由JOBS 参数化的模板类,它找到Worker 来执行job。对于JOBS 中的每个作业类型,JobPlant 继承自 Work。 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);
}
【问题讨论】:
标签: c++ templates c++11 polymorphism variadic-templates