Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function with multiple return types

Tags:

c++

c++11

I have two enums which basically determine (on runtime) what to do. The 'mapping' looks something like

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());

The problem is, that a, b and C, as well as the return types of x() and y() are all of different types (some really huge template types).

Mapping the two enums using switches or ifs is pretty ugly and requires lots of effort so I wondered, if I could somehow write something like this:

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)));

Edit 1: I can not edit the classes CA, CB and CC. I also can not edit the classes/return types of x() and y(). All those types come from an external library.

like image 678
Uroc327 Avatar asked Aug 30 '16 10:08

Uroc327


1 Answers

You can use continuation passing style.

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);
  }
}

Where instead of returning, you pass the next step as a parameter to the previous.

Func f;
Base b;
Foo foo;

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

or somesuch (there may be typos).

std::variant (or boost) can be used to move the continuation until after the return value.

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

where instead of taking a continuation, each of the above returns a variant<possible_return_types_go_here>.

like image 115
Yakk - Adam Nevraumont Avatar answered Sep 26 '22 04:09

Yakk - Adam Nevraumont