Search code examples
c++c++11refactoringusingtype-alias

Type alias for function arguments in C++


I have a function like this:

template <typename P1, typename... Ps> constexpr auto pipe(P1 &&proc1,
  Ps &&...procs) -> Cont<Cont<
    Proc<typename RevProc<P1>::ArgType,
      typename RevProc<typename Last<Ps...>::Type>::RetType>>> {
  using T = typename RevProc<P1>::ArgType;
  using U = typename RevProc<P1>::RetType;
  using V = typename RevProc<typename Last<Ps...>::Type>::RetType;
  return [&] (Cont<Proc<T, V>> &&pass) {
    pipe(move(procs)...)([&] (Proc<U, V> &&proc2) {
      pipe(move(proc1), move(proc2))(move(pass));
    });
  };
}

As you may find out that the type declaration is duplicated. Is there any chance to give this function a signature like:

template <typename P1, typename... Ps> constexpr auto pipe(P1 &&proc1,
  Ps &&...procs) -> Cont<Cont<Proc<T, V>>>

and define T and V at some proper position?


Solution

  • In C++14, you can just let the type be deduced:

    template <typename P1, typename... Ps>
    constexpr auto pipe(P1 &&proc1, Ps &&...procs) {
      using T = typename RevProc<P1>::ArgType;
      using U = typename RevProc<P1>::RetType;
      using V = typename RevProc<typename Last<Ps...>::Type>::RetType;
      return Cont<Cont<Proc<T, V>>>([&](Cont<Proc<T, V>> &&pass) {
        pipe(std::move(procs)...)([&](Proc<U, V> &&proc2) {
          pipe(std::move(proc1), std::move(proc2))(std::move(pass));
        });
      });
    }
    

    By the way, some of your uses of std::move doesn't look legitimate, since pipe may well be called with lvalues that the caller doesn't expect to be moved from. It's better to actually forward what you take by forwarding reference:

      return Cont<Cont<Proc<T, V>>>([&](Cont<Proc<T, V>> &&pass) {
        pipe(std::forward<Ps>(procs)...)([&](Proc<U, V> &&proc2) {
          pipe(std::forward<P1>(proc1), std::move(proc2))(std::move(pass));
        });
      });