C++ 具有多个返回类型的函数

C++ 具有多个返回类型的函数,c++,c++11,C++,C++11,我有两个枚举,它们基本上决定(在运行时)要做什么。“映射”看起来像 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 =

我有两个枚举,它们基本上决定(在运行时)要做什么。“映射”看起来像

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()
的返回类型都是不同的类型(一些非常庞大的模板类型)

使用开关或ifs映射这两个枚举非常难看,需要付出很多努力,因此我想知道,我是否可以这样写:

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)));
structfoo{class CA;class CB;class CC;CA a;CB b;CC c;};
枚举基{A,B,C,};
枚举函数{X,Y,};
模板自动应用程序函数(函数f,T)
{
开关(f)
{
案例X:返回t.X();
案例Y:返回t.Y();
}
}
自动获取基本(基本b,基本f)
{
开关(b)
{
案例A:返回f.A;
案例B:返回f.B;
案例C:返回f.C;
}
}
函数f;
碱基b;
富富,;
使用(applyFunc(f,getBase(b,foo));
编辑1:
我无法编辑类
CA
CB
CC
。我也不能编辑
x()
y()
的类/返回类型。所有这些类型都来自外部库。

简而言之:您不能。函数的返回类型必须在编译时已知。事实上,尝试在函数中使用
auto
返回类型返回不同的类型,即使使用模板,也会导致编译器错误


您的解决方案可能包括使用polymorfism。

函数应始终返回在编译时确定的具有相同数据类型的值。例如,您可以使用某种形式的变体,或创建自己的变体类型:

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; }
};
类结果\u处理程序{
公众:
虚~result_handler(){}
虚空句柄_字符串(字符串s)=0;
虚空句柄_int(int i)=0;
虚空句柄_double(double d)=0;
};
空f(整数x,结果处理程序*h){
开关(x){
案例0:
h->handle_字符串(f1());
打破
案例1:
h->handle_int(f2());
打破
案例2:
h->handle_double(f3());
打破
}
}
类my_result_处理程序:public result_处理程序{
公众:

虚空句柄_string(string s){cout您可以使用延续传递样式

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);
  }
}
或者类似的(可能有打字错误)

std::variant
(或boost)可用于将延续移动到返回值之后

auto b = getBase(b);
auto r = visit( b, [&](auto&& b){ return applyFunc( f, b ); } );
visit( r, [](auto&& r){ use(r); } );

其中,上述每种方法都返回一个
变量,而不是继续执行。如果编译时参数已知,则可以使用标记分派:

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>{}); }
模板基标签{};
decltype(auto)getBaseImpl(Foo&Foo,BaseTag){return Foo.a;}
decltype(auto)getBaseImpl(Foo&Foo,BaseTag){return Foo.b;}
decltype(auto)getBaseImpl(Foo&Foo,BaseTag){return Foo.c;}
模板
decltype(auto)getBase(Foo&Foo){return getBaseImpl(Foo,BaseTag{});}
模板FuncTag{};
模板
decltype(auto)getFuncImpl(T&T,FuncTag){return T.x();}
模板
decltype(auto)getFuncImpl(T&T,FuncTag){return T.y();}
模板
decltype(auto)getFunc(T&T){return getFuncImpl(f,FuncTag{});}
最后:

template <Base base, Func func>
decltype(auto) getElem(Foo& foo) { return getFunc<func>(getBase<base>(foo)); }
模板
decltype(auto)getElem(Foo&Foo){return getFunc(getBase(Foo));}

另一个解决方案是使用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);
}
struct Foo{class CA{};class CB{};class CC{};CA a;CB b;CC c;};
枚举基{A,B,C,};
枚举函数{X,Y,};
模板结构GetBaseTraits;
模板结构GetBaseTraits{using type=Foo::CA;};
模板结构GetBaseTraits{using type=Foo::CB;};
模板结构GetBaseTraits{using type=Foo::CC;};
模板
typename-GetBaseTraits::type-getBase(Foo-f);
模板typename GetBaseTraits::type getBase(Foo f){return f.a;}
模板typename GetBaseTraits::type getBase(Foo f){return f.b;}
模板typename GetBaseTraits::type getBase(Foo f){return f.c;}
int main(){
富福{};
Foo::CA=getBase(f);
Foo::CB CB=getBase(f);
Foo::CC=getBase(f);
}

哼哼……想成为……你想实现什么?你想用这种设计实现什么真正的问题?我想到的第一个想法是你试图重新实现
virtual
inheritance你做不到。在运行时决定使用哪个模板总是会在每次使用时导致丑陋的切换,而你无法将其分解为函数。其次是多态性,该函数返回一个实际指向正确类(工厂模式)的
唯一\u ptr
。@nwp在某些情况下,可以编写编译器生成的跳转表来替换开关。或链ifs。或者…这只是有时的改进,但使用“始终”是完全错误的。@Yakk您是对的,您可以使用if-chains或goto实现切换,并说您没有使用switch。从技术上讲,这是错误的。目的是避免每次使用都必须编写映射代码,而不是避免使用switch关键字。@nwp或我可以从两个平行列表中生成mappimg如果我控制了枚举,枚举的值就是一个足够的列表。我的观点是你提出了一个过于强烈的主张,我们不知道什么标准可以使解决方案“更好”比OP的switch语句更重要。此外,OP正在询问如何使两个独立的switch语句工作,这也是非常可行的。但是当
getBase
的模板参数是一个运行时变量时,这不起作用,对吗?@Uroc327对。我不明白这是一个要求。如果是这样,我会在一段时间内删除答案。
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);
}