我正在寻找一种解决方案,以解决C ++中缺少虚拟模板功能的问题。 我理想上希望的是能够将派生类存储在向量中,对其进行迭代并调用正确的函数,因此使用伪代码:
template<typename T>
struct Output
{
...
};
struct Base
{
template<typename T>
virtual void doSomething(Output<T>& out) = 0;
};
struct DerivedA : public Base
{
DerivedA(const char* filename) {...}
template<typename T>
void doSomething(Output<T>& out) final
{
...
}
};
struct DerivedB : public Base
{
DerivedB(const char* filename) {...}
template<typename T>
void doSomething(Output<T>& out) final
{
...
}
};
int main()
{
std::vector<Base*> vec;
vec.push_back(new DerivedA("data1.bin"));
vec.push_back(new DerivedB("data2.bin"));
vec.push_back(new DerivedA("data3.bin"));
vec.push_back(new DerivedA("data4.bin"));
Output<float> outF;
Output<double> outD;
Output<int> outI;
for (auto e : vec)
{
e->doSomething(outF);
e->doSomething(outD);
e->doSomething(outI);
}
return 0;
}
如果变通办法尽可能“无痛”且不冗长,则我更希望这样做(因为我使用模板的目的是避免对n种不同类型的n重复定义相同的函数n次)。我想到的是使用std :: map使自己成为vtable,并进行一些dynamic_casts。我正在寻找任何更好的想法,或者如果您认为在这种情况下最好的话,甚至是该想法的简洁实现。我正在寻找一种理想的解决方案,其介入最少,并且很容易添加新类。
编辑: 我想出了一种解决方法,但它包括一些冗长的内容(但至少避免了非平凡的代码重复):
struct Base
{
virtual void doSomething(Output<int>& out) = 0;
virtual void doSomething(Output<float>& out) = 0;
virtual void doSomething(Output<double>& out) = 0;
private:
template<typename T>
void doSomething(Output<T>& out)
{
std::cout << "Base doSomething called with: " << typeid(T).name() << "\n";
}
};
struct DerivedA : public Base
{
void doSomething(Output<int>& out) final
{
doSomething<int>(out);
}
void doSomething(Output<float>& out) final
{
doSomething<float>(out);
}
void doSomething(Output<double>& out) final
{
doSomething<double>(out);
}
private:
template<typename T>
void doSomething(Output<T>& out)
{
std::cout << "DerivedA doSomething called with: " << typeid(T).name() << "\n";
}
};
struct DerivedB : public Base
{
void doSomething(Output<int>& out) final
{
doSomething<int>(out);
}
void doSomething(Output<float>& out) final
{
doSomething<float>(out);
}
void doSomething(Output<double>& out) final
{
doSomething<double>(out);
}
private:
template<typename T>
void doSomething(Output<T>& out)
{
std::cout << "DerivedB doSomething called with: " << typeid(T).name() << "\n";
}
};
有人有什么更好的主意,而又不必一遍又一遍地重新定义相同的功能吗?理想情况下,它将在基类中定义一次,CRTP似乎无济于事。动态转换似乎是另一个明智的选择。
答案 0 :(得分:0)
尝试这样的事情:
struct OutputBase
{
virtual void doSomething() = 0;
};
template<class T >
struct Output : public OutputBase
{
virtual void doSomething()
{
std::cout << typeid(T).name();
}
};
struct Base
{
virtual void doSomething(OutputBase* out) = 0;
};
struct DerivedA : public Base
{
virtual void doSomething(OutputBase* out)
{
std::cout << "DerivedA doSomething called with: ";
out->doSomething();
std::cout<< std::endl;
}
};
struct DerivedB : public Base
{
virtual void doSomething(OutputBase* out)
{
std::cout << "DerivedB doSomething called with: ";
out->doSomething();
std::cout << std::endl;
}
};
int main()
{
OutputBase* out_int = new Output < int > ;
OutputBase* out_double = new Output < double >;
Base* a = new DerivedA;
a->doSomething(out_int);
a->doSomething(out_double);
Base* b = new DerivedB;
b->doSomething(out_int);
b->doSomething(out_double);
return 0;
}
如果不想更改输出,可以在Output周围使用包装器。