我想编写一个函数,根据不同的输入返回不同的类型,如下所示。
enum MyType
{
A,
B
};
template<MyType T> struct MyStruct
{
};
static auto createMyStruct(MyType t)
{
if(t==A)
return MyStruct<A>();
else
return MyStruct<B>();
}
它没有成功,因为一个汽车有两种返回类型。有没有其他方法可以做到这一点?
答案 0 :(得分:1)
绝对没有办法让(单个)函数根据运行时决策返回不同的类型。返回类型必须在编译时知道。但是,您可以使用模板函数,这样(感谢@dyp使我简化代码):
#include <iostream>
#include <typeinfo>
enum MyType
{
A,
B
};
template<MyType>
struct MyStruct {};
template<MyType type>
MyStruct<type> createMyStruct()
{
return {};
}
int main()
{
auto structA = createMyStruct<A>();
auto structB = createMyStruct<B>();
std::cout << typeid(structA).name() << std::endl;
std::cout << typeid(structB).name() << std::endl;
}
答案 1 :(得分:0)
我认为你应该学习abstract factory design pattern。
对于MyStruct<A>
或MyStruct<B>
类型的使用对象,您需要通用接口。抽象基类中提供的通用接口。
struct MyStruct
{
virtual ~MyStruct() {}
virtual void StructMethod() = 0;
};
struct MyStructA: public MyStrcut
{
void StructMethod() override {}
};
struct MyStructB: public MyStrcut
{
void StructMethod() override {}
};
std::unique_ptr<MyStruct> createMyStruct(MyType t)
{
if(t==A)
return std::make_unique<MyStructA>();
else
return std::make_unique<MyStructB>();
}
答案 2 :(得分:0)
我假设你想写这样的代码:
void foo (MyType t) {
auto x = createMyStruct(t);
//... do something with x
}
您正试图在运行时为x
派生正确的类型。但是,必须在编译时知道函数的返回类型,并且auto
的类型解析也在编译时确定。
您可以改为将代码重构为:
template<MyType T> struct MyStruct
{
//...
static void foo () {
MyStruct x;
//... do something with x
}
};
这个想法是编写一个foo()
函数,它唯一的区别就是它操作的东西的类型。此函数封装在类型本身中。如果您在MyType
和MyStruct<MyType>::foo
之间存在映射,则现在可以做出运行时决策。
typedef std::map<MyType, void(*)()> MyMap;
template <MyType...> struct PopulateMyMap;
template <MyType T> struct PopulateMyMap<T> {
void operator () (MyMap &m) {
m[T] = MyStruct<T>::foo;
}
};
template <MyType T, MyType... Rest> struct PopulateMyMap<T, Rest...> {
void operator () (MyMap &m) {
m[T] = MyStruct<T>::foo;
PopulateMyMap<Rest...>()(m);
}
};
template<MyType... Types> void populateMyMap (MyMap &m) {
PopulateMyMap<Types...>()(m);
}
//...
populateMyMap<A, B>(myMapInstance);
然后,做出运行时决定:
void foo (MyType t) {
myMapInstance.at(t)();
}