Giovanni Botta
Giovanni Botta

Reputation: 9816

Convert arguments of variadic function

This is probably a newbie question but I thought it might be interesting. Let's say I have this function:

template <typename First, typename... T>
int ComputeSomething(const First& f, const T&... t);

I would like to write a second function that calls the one above in the general case, but converts the arguments when First and T are of type float, i.e., it calls a Convert function on each argument:

long Convert(float f);

template <typename First, typename... T>
int MyFun(const First& f, const T&... t) {
  return ComputeSomething(f, t...);
}

// This is what I would like:
int MyFun(const float& f, const float& t...) {
  return ComputeSomething(Convert(f), Convert(t)...);
}

How can I achieve that?

Upvotes: 1

Views: 139

Answers (2)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48447

Add a transparent Convert overload, so that non-floats are bypassed (that is, you can have mixed types of arguments):

template <typename First, typename... T>
int ComputeSomething(const First& f, const T&... t);

long Convert(float f);

// Transparent converter
template <typename T>
T&& Convert(T&& t) { return std::forward<T>(t); }

template <typename First, typename... Ts>
int MyFun(const First& f, const Ts&... t)
{
    return ComputeSomething(Convert(f), Convert(t)...);
}

DEMO

Upvotes: 3

Daniel Frey
Daniel Frey

Reputation: 56863

You could use a helper to test if all types are float:

#include <type_traits>

template< typename... > struct typelist {};

template< typename T, typename... Ts >
using is_all_same = std::is_same< typelist< T, Ts... >,
                                  typelist< Ts..., T > >;

long Convert(float f);

template <typename First, typename... T>
typename std::enable_if< !is_all_same< float, First, T... >::value, int >::type
MyFun(const First& f, const T&... t) {
  return ComputeSomething(f, t...);
}

template <typename First, typename... T>
typename std::enable_if< is_all_same< float, First, T... >::value, int >::type
MyFun(const First& f, const T&... t) {
  return ComputeSomething(Convert(f), Convert(t)...);
}

The helper is quite generic and can be used in other contexts as well.

EDIT: I replaced std::tuple with typelist, although the tuple would never be instantiated in the above context. I was just using it for convenience, but since some people think it is too much overhead, I edited the answer.

Upvotes: 2

Related Questions