Create class based on variadic templates

Lets imagine that we have several data flows and we need unite them to one. Capacity of flows (and type) is known at application level. So we need class that incapsulates all other classes that relates to each data flow and produces common frame based on return type of data flows. Each data flow class have next interface:

// note that there are several classes with similar interface
class FlowOne {
  using return_type = some_data;

  return_type get();
};

Main flow class will look like:

template <typename... Args>
class Main {
  using return_type = *based on Args::return_type*;
  return_type get();
};

So, here is a question: how to define Main::return_type – that should be a tuple of return_type-s from its Args? Is it possible?

Thanks

>Solution :

You can expand Args... to be std::tuple<Args...> and declare a member of that type. Now your Main class has a tuple of all Flow types:

template <typename... Args>
struct Main {
    using tuple_type = std::tuple<Args...>;
    tuple_type members;

the next step is to make a get() function that returns the .get() of all members. This can be achieved with std::apply to iterate over the tuple, and call .get() on each object. Keep in mind that, if your final get() functions return a reference, this get() should also return one (meaning auto& or auto&&).

auto get() {
    return std::apply([](auto&&... member) {
        return std::make_tuple(member.get()...);
    }, this->members);
}

As you can see, if we say decltype(get) on the member function, it will be equal to the std::tuple of Flow types:

struct FlowOne {
    using return_type = int;

    return_type get() {
        return {};
    }
};
struct FlowTwo {
    using return_type = double;
    return_type get() {
        return {};
    }
};

int main() {
    Main<FlowOne, FlowTwo> main;
    auto get = main.get();

    static_assert(std::is_same_v<decltype(get), std::tuple<int, double>>);
}

if you still wish to define a Main::return_type, you can use this using statement:

using return_type = std::tuple<typename Args::return_type...>;

we have to add typename here, because return_type is a dependant type of Args. You can read more about this on this post


Try out the full code on godbolt.

Leave a Reply