具有多个返回类型的函数
Function with multiple return types
我有两个枚举,它们基本上决定(在运行时)要做什么。"映射"看起来像
struct Foo { class CA; class CB; class CC; CA a; CB b; CC c; };
enum Base { A, B, C };
enum Func { X, Y };
Foo foo;
// A, X => use(foo.a.x());
// A, Y => use(foo.a.y());
// B, X => use(foo.b.x());
// B, Y => use(foo.b.y());
问题是,a
、b
、C
,以及x()
、y()
的返回类型都是不同的类型(有些模板类型真的很大)。
使用开关或if映射两个枚举是非常丑陋的,需要大量的工作,所以我想知道,如果我能以某种方式写这样的东西:
struct Foo { class CA; class CB; class CC; CA a; CB b; CC c; };
enum Base { A, B, C, };
enum Func { X, Y, };
template <typename T> auto applyFunc(Func f, T t)
{
switch(f)
{
case X: return t.x();
case Y: return t.y();
}
}
auto getBase(Base b, Foo f)
{
switch(b)
{
case A: return f.a;
case B: return f.b;
case C: return f.c;
}
}
Func f;
Base b;
Foo foo;
use(applyFunc(f, getBase(b, foo)));
编辑1:我不能编辑CA
, CB
和CC
类。我也不能编辑x()
和y()
的类/返回类型。所有这些类型都来自外部库。
可以使用延续传递样式
template <class F> void applyFunc(WhichFunc w, T t, F f)
{
switch(w)
{
case X: f(t.x());
case Y: f(t.y());
}
}
template<class F>
void getBase(Base b, Foo foo, F f)
{
switch(b)
{
case A: f(foo.a);
case B: f(foo.b);
case C: f(foo.c);
}
}
其中不返回,而是将下一步作为参数传递给前一步。
Func f;
Base b;
Foo foo;
getBase(b, [&](auto&&b){ applyFunc( f, b, [&](auto&& r){ use(r); } ); } );
或类似的东西(可能有错别字)。
std::variant
(或boost)可用于将延续移动到返回值之后。
auto b = getBase(b);
auto r = visit( b, [&](auto&& b){ return applyFunc( f, b ); } );
visit( r, [](auto&& r){ use(r); } );
,上面的每个都返回一个variant<possible_return_types_go_here>
,而不是一个延续。
简而言之:你不能。函数的返回类型必须在编译时是已知的。事实上,试图在一个函数中返回不同类型的auto
返回类型,它会给你一个编译错误,即使你使用模板。
可能你的解决方案包括使用多态。
另一个解决方案是使用traits:
struct Foo { class CA {}; class CB {}; class CC {}; CA a; CB b; CC c; };
enum Base { A, B, C, };
enum Func { X, Y, };
template<Base> struct GetBaseTraits;
template<> struct GetBaseTraits<Base::A> { using type = Foo::CA; };
template<> struct GetBaseTraits<Base::B> { using type = Foo::CB; };
template<> struct GetBaseTraits<Base::C> { using type = Foo::CC; };
template<Base b>
typename GetBaseTraits<b>::type getBase(Foo f);
template<> typename GetBaseTraits<A>::type getBase<A>(Foo f) { return f.a; }
template<> typename GetBaseTraits<B>::type getBase<B>(Foo f) { return f.b; }
template<> typename GetBaseTraits<C>::type getBase<C>(Foo f) { return f.c; }
int main() {
Foo f{};
Foo::CA ca = getBase<A>(f);
Foo::CB cb = getBase<B>(f);
Foo::CC cc = getBase<C>(f);
}
函数应始终返回具有相同数据类型的值,这些值在编译时确定。您可以使用某种形式的变体,例如boost::variant,或者创建您自己的变体类型:
enum ReturnType {
RET_STR, RET_INT, RET_DBL
};
struct variant {
ReturnType valtype;
string str;
int i;
double d;
};
string f1() { ... }
int f2() { ... }
double f3() { ... }
variant f(int x) {
variant v;
switch (x) {
case 0:
v.valtype = RET_STR;
v.str = f1();
break;
case 1:
v.valtype = RET_INT;
v.str = f2();
break;
case 2:
v.valtype = RET_DBL;
v.str = f3();
break;
}
return v;
}
或者,您可以使用某种形式的多态性:
class result_handler {
public:
virtual ~result_handler(){}
virtual void handle_string(string s) = 0;
virtual void handle_int(int i) = 0;
virtual void handle_double(double d) = 0;
};
void f(int x, result_handler* h) {
switch (x) {
case 0:
h->handle_string(f1());
break;
case 1:
h->handle_int(f2());
break;
case 2:
h->handle_double(f3());
break;
}
}
class my_result_handler : public result_handler {
public:
virtual void handle_string(string s) { cout << "string " << s << endl; }
virtual void handle_int(int i) { cout << "int " << i << endl; }
virtual void handle_double(double d) { cout << "double " << d << endl; }
};
如果参数在编译时已知,则可以使用标记调度:
template <Base> BaseTag{};
decltype(auto) getBaseImpl(Foo& foo, BaseTag<Base::A>) { return foo.a; }
decltype(auto) getBaseImpl(Foo& foo, BaseTag<Base::B>) { return foo.b; }
decltype(auto) getBaseImpl(Foo& foo, BaseTag<Base::C>) { return foo.c; }
template <Base base>
decltype(auto) getBase(Foo& foo) { return getBaseImpl(foo, BaseTag<base>{}); }
template <Func> FuncTag{};
template <typename T>
decltype(auto) getFuncImpl(T& t, FuncTag<Func::X>) { return t.x(); }
template <typename T>
decltype(auto) getFuncImpl(T& t, FuncTag<Func::Y>) { return t.y(); }
template <typename T, Func func>
decltype(auto) getFunc(T& t) { return getFuncImpl(f, FuncTag<func>{}); }
最后:
template <Base base, Func func>
decltype(auto) getElem(Foo& foo) { return getFunc<func>(getBase<base>(foo)); }
相关文章:
- 检查函数返回类型是否与STL容器类型值相同
- 警告:在函数返回类型 [-Wignore 限定符] 时忽略类型限定符
- 在 c++ 中将函数返回类型指定为模板参数
- 通过引用传递参数;函数返回类型是否必须为 VOID?
- 如何避免模板函数返回类型重复?
- 从类型bankAccount的返回值到函数返回类型int没有可行的转换
- 为什么在某些情况下从函数返回类型中删除 cv 限定符?
- 模板类内模板类的函数返回类型
- 为什么函数返回类型中不允许参数推导?
- 函数返回类型之前的"define"
- C++推断要隐式调用的模板函数返回类型
- 具有不同模板参数的函数返回类型
- 当函数返回类型为父类时,如何返回子类的对象?
- C++:在原型中声明"auto"函数返回类型仍然会导致在扣除错误之前使用"auto&quo
- C++14 'auto'能够获取函数返回类型,我们还需要 std::result_of<> 吗?
- 函数返回类型中的模板类型推断
- 嵌套模板类返回类型在 C++ 中的头文件中函数返回类型的语法
- C++重写 void 函数返回类型会导致生成失败
- 从函数内部推断函数返回类型
- C++嵌套类函数返回类型和命名空间