Using ‘void’ template arguments in C++

The short answer is “templates are not string substitution”. void f(void) has meaning only so far as it is an alias for void f() in C++, in order to be backwards compatible with C.

The first step is to use variadics, as noted elsewhere.

The second step is figuring out how to map void returning functions to … well, maybe something like std::function<void()>, or maybe something else. I say maybe something else because unlike the other cases, you cannot call std::function<void()> foo; foo( []()->void {} ); — it isn’t a true continuation.

Something like this maybe:

template<typename T>
struct Continuation
{
  typedef std::function<void(T)> type;
};

template<>
struct Continuation<void>
{
  typedef std::function<void()> type;
};

then use it like this:

auto someFunc = []()->void {};
Continuation<decltype(someFunc())>::type c;

which gives you the type you want. You could even add in an apply to continuation:

template<typename T>
struct Continuation
{
  typedef std::function<void(T)> type;

  template<typename func, typename... Args>
  static void Apply( type const& cont, func&& f, Args... args)
  {
    cont( f(args...) );
  }
};

template<>
struct Continuation<void>
{
  typedef std::function<void()> type;
  template<typename func, typename... Args>
  static void Apply( type const& cont, func&& f, Args... args)
  {
    f(args...);
    cont();
  }
};

which lets you apply a continuation to an execution of a function uniformly if the incoming type is a void or if it is a non-void type.

However, I would ask “why would you want to do this”?

Leave a Comment