Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function with nested variadic template

Can you write a function using variadic templates that accepts an arbitrary list of tuples, each with a different set of parameters? So you would have something like:

template< /* some crazy variadic thing...*/ >
void func( ... ) {}

func(make_tuple(1,2), make_tuple("hello"));

SFINAE to the rescue! Taking Jeffery's answer a little further, I wrote this little snippet. You can put types other than tuples anywhere in the argument list for func and it will compile and run, it will just break my printing chain when it hits the first type that isnt a template class. seq and gens come from here.

template<typename T>
int print(T& t) {
        cout << t << " ";
        return 0;
}

template<typename... T> void dumby(T...) {}

// so other template classes don't cause error (see bar below)
template<typename... A>
void expand(A... a) {}

template<typename... A, int... S>
void expand(tuple<A...> a, seq<S...>) {
        dumby(print(get<S>(a))...);
        cout << endl;
}

template<class... Types>
void func(Types...) {}

template<template<typename...> class A, class... Types, class... tup_types>
void func(A<tup_types...> a, Types... args) {
        expand(a, typename gens<sizeof...(tup_types)>::type());

        func(args...);
}

template<typename... A> struct bar {};

int main () {
        func(make_tuple(0,1), make_tuple(2), 1, make_tuple("hello"), 0);
        func(make_tuple(0,1), bar<int,int>(), make_tuple(2), 1, make_tuple("hello"), 0);
}

I'll have to find a practical use case to try it out but I'll call that a tentative success!

like image 408
chuck1 Avatar asked Mar 20 '23 15:03

chuck1


1 Answers

Yes, just use a base function taking a tuple then make a function of the same name with variadic templates/parameters.

template<typename ... Types>
void func(const std::tuple<Types...> &Tuple){
    // work with tuple
}

template<typename TupleType, typename ... TupleTypes>
void func(const TupleType &arg, const TupleTypes &... args){
    func(arg);
    func(args...);
}

int main(){
    func(std::make_tuple(1, 2), std::make_tuple("hello"));
}

This will give you a lot of flexibility in that you can know the number of types in the tuple and throw or static_assert or whatever you like when you come across something you don't like OR you could go even further and use std::enable_if on the function to only allow certain conditions with your tuples!

This function will only work with std::tuple as you asked, but you could expand it further to allow the use of any container that takes multiple template arguments for it's types by changing the first function to:

template<typename ... Types, template<typename...> class TupleType>
void func(const TupleType<Types...> &Tuple){
    // Work with any type inter-face-able like a tuple
}

EDIT

This can be made a little more terse with C++17 fold expressions:

template<typename ... Ts>
void func(const std::tuple<Types...> &Tuple){
    // ...
}

template<typename ... Tuples>
void func(const Tuples &... tuples){
    (func(tuples), ...);
}
like image 58
RamblingMad Avatar answered Mar 29 '23 17:03

RamblingMad