TangKe
TangKe

Reputation: 378

C++ void argument with variadic template

I have the following template in my C++ class:

template <typename ReturnType, typename... Args>
ReturnType run(void* context, const Args&... args) {
  /* Do the actual job. */
}

For practical reason, I need to specify it for ReturnType void. I need to keep the list of args because they are still useful.

I tried the following but neither works:

template <typename... Args>
void run(void* context, const Args&... args) {
  /* Do the actual job. */
}

and

template <typename ReturnType = void, typename... Args>
void run(void* context, const Args&... args) {
  /* Do the actual job. */
}

So.. what is the correct way to specify with the void argument in my example?

Upvotes: 1

Views: 1746

Answers (1)

Barry
Barry

Reputation: 303107

In C++17, this is simple: use if constexpr:

template <typename ReturnType, typename... Args>
ReturnType run(void* context, const Args&... args) {
    if constexpr (std::is_void_v<ReturnType>) {
        /* void case */
    } else {
        /* non-void case */
    }
}

Before C++17, the best way to do this is with tag dispatching. Create a new class template that just encodes the type, so that you can pass it as an argument:

template <typename T> struct tag { };

template <typename ReturnType, typename... Args>
ReturnType run_impl(tag<ReturnType>, void* context, const Args&... args) {
    /* non-void case */
}

template <typename... Args>
void run_impl(tag<void>, void* context, const Args&... args) {
    /* void case */
}

template <typename ReturnType, typename... Args>
ReturnType run(void* context, const Args&... args) {
    return run_impl(tag<ReturnType>{}, context, args...);
}

Upvotes: 6

Related Questions