我遇到的问题对我来说有点太大了。搜索它是另一个复杂的问题,因为我无法想象究竟要搜索什么。所以我希望有人能指出我正确的方向。
当使用枚举实现工厂来挑选作为模板类的变体时,会出现问题。问题是即使对于不可能的情况,编译器也会执行类型检查。最小的例子如下:
template <class T1, class T2>
class Base {
public:
Base() {}
};
template <class T1>
class A : public Base<T1, T1> {
public:
A(): Base<T1, T1>() {}
};
template <class T1, class T2>
class B : public Base<T1, T2> {
public:
B(): Base<T1, T2>() {}
};
enum class Type {
TYPE_A, TYPE_B
};
class Factory {
public:
template<class T1, class T2>
static Base<T1, T2>* Create(Type type) {
switch (type) {
case Type::TYPE_A:
return new A<T1>();
case Type::TYPE_B:
return new B<T1, T2>();
}
return nullptr;
}
};
int main(int argc, char const * argv[]) {
Base<int, double>* ptr = Factory::Create<int, double>(Type::TYPE_B);
delete ptr;
return 0;
}
并为您不想运行此操作的人显示错误消息:
test_template_factory.cpp: In instantiation of ‘static Base<T1, T2>* Factory::Create(Type) [with T1 = int; T2 = double]’:
test_template_factory.cpp:38:69: required from here
test_template_factory.cpp:29:26: error: cannot convert ‘A<int>*’ to ‘Base<int, double>*’ in return
return new A<T1>();
^
有解决方法吗?有没有一种方法可以避免它同时保持灵活性?提前谢谢!
答案 0 :(得分:2)
您应该选择在编译时执行的操作,而不是在运行时。
这样的事情可以帮助你。
template <class T1, class T2>
class Base {
public:
Base() {}
};
template <class T1>
class A : public Base<T1, T1> {
public:
A(): Base<T1, T1>() {}
};
template <class T1, class T2>
class B : public Base<T1, T2> {
public:
B(): Base<T1, T2>() {}
};
enum class Type {
TYPE_A, TYPE_B
};
class Factory {
public:
template<Type type, class T1, class T2>
static Base<T1, T2>* Create() {
return create_helper<type, T1, T2>::apply();
}
private:
template<Type type, class T1, class T2>
struct create_helper
{
static Base<T1, T2>* apply() { return nullptr; }
};
};
template<class T1, class T2>
struct Factory::create_helper<Type::TYPE_A, T1, T2>
{
static Base<T1, T2>* apply() { return new A<T1>(); }
};
template<class T1, class T2>
struct Factory::create_helper<Type::TYPE_B, T1, T2>
{
static Base<T1, T2>* apply() { return new B<T1, T2>(); }
};
int main(int argc, char const * argv[]) {
Base<int, double>* ptr = Factory::Create<Type::TYPE_B, int, double>();
delete ptr;
return 0;
}
答案 1 :(得分:1)
您的设计的主要问题是您无法为任意 A
和T1
创建T2
。想象一下你的代码是
Base<int, double>* ptr = Factory::Create<int, double>(Type::TYPE_A);
这绝对是一个错误,因为A
&#39}都不是Base<int, double>
的子类。这是编译器观察到的错误,因为当它进行Factory::Create<int, double>
的实例化时,它还不知道你会将TYPE_B
传递给它。
可能的解决方案是为Factory::Create<T1,T1>
提供专业化,类似于以下内容:
template<class T1, class T2>
class Factory {
public:
static Base<T1, T2>* Create(Type type);
};
template<class T1>
class Factory<T1,T1> {
public:
static Base<T1, T1>* Create(Type type);
};
template<class T1, class T2>
Base<T1, T2>* Factory<T1,T2>::Create(Type type)
{
switch (type) {
case Type::TYPE_A:
throw "can't create A";
case Type::TYPE_B:
return new B<T1, T2>();
}
return nullptr;
}
template<class T1>
Base<T1, T1>* Factory<T1,T1>::Create(Type type)
{
switch (type) {
case Type::TYPE_A:
return new A<T1>();
case Type::TYPE_B:
return new B<T1, T1>();
}
return nullptr;
}
...
Base<int, int>* ptr1 = Factory<int, int>::Create(Type::TYPE_B);
Base<int, int>* ptr2 = Factory<int, int>::Create(Type::TYPE_A);
Base<int, double>* ptr3 = Factory<int, double>::Create(Type::TYPE_B);
Base<int, double>* ptr4 = Factory<int, double>::Create(Type::TYPE_A); // throws
请注意,我将模板参数移到了类中以允许部分特化。