nyarlathotep108
nyarlathotep108

Reputation: 5523

Two packs of variadic template arguments

I have a variadic template function F which must be called upon exactly two objects. Another function, called G, will therefore call F twice, once for object one and the other one for object two. G is therefore also variadic, but the problem is that the two variadic parameters packs for the two calls on F can be different, and G must know which to call upon object one and which upon object two:

template< typename ...Args>
void F(Obj obj);

template<typename ...Args1, typename ...Args2>
void G(Obj obj_1, Ojb obj_2)
{
    F<Args1...>( obj_1 );
    F<Args2...>( obj_2 );
}

Now if I call G, which version of F is called upon obj_1 and which upon obj_2? How can this be correctly specified when calling G?

Upvotes: 1

Views: 58

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275230

Tags are a great plan. If you don't want to use tags, you can use lambdas.

In we can do

template<class...Args1>
auto G() {
  return []<class...Args2>() {
    F<Args1...>( obj_1 );
    F<Args2...>( obj_2 );
  };
}

now calling this is a big ugly.

G<int>().operator()<double, char>();

we can clean this up with ... tags. This also only requires :

template<class T>
struct tag_t { using type=T; };
template<class T>
constexpr tag_t<T> tag{};

template<class...Args1>
auto G(tag_t<Args1>...) {
  return [](auto...args2) {
    F<Args1...>( obj_1 );
    F<typename decltype(args2)::type...>( obj_2 );
  };
}

now calling this becomes:

G(tag<int>)(tag<double>, tag<char>);

which is more fun.

Upvotes: 1

Jarod42
Jarod42

Reputation: 217085

using Tag might help here, as you cannot partial specialize function:

template <typename ... Ts>
struct Tag {};

template< typename ...Args>
void F(Obj obj) { /*...*/ }

template<typename ...Args1, typename ...Args2>
void G(Tag<Args1...>, Obj obj_1, Tag<Args2...>, Ojb obj_2)
{
    F<Args1...>( obj_1 );
    F<Args2...>( obj_2 );
}

Upvotes: 2

Related Questions