add two variadic template list of integers

Related searches

Given this type

template<std::size_t N, int ...content>
struct list {
    inline int reduce() {
        int result = 0;
        constexpr int arr[N] = { content... };
        for(std::size_t k = 0; k < N; ++k) {
            result += arr[k];
        }

        return result;
    }
};

I'd like to implement a function add, which returns a new list containing the element-by-element addition of the two input lists. In other words (pseudo-code):

add([a0, a1, a2], [b0, b1]) -> [a0 + b0, a1 + b2, a2]

Problem:

  • I don't even know how to declare the return type of such a function
  • and i don't know if it's possible

Here is how I would do it:

#include <iostream>
#include <utility>

template<std::size_t N, int ...content>
struct list {
    inline int reduce() {
        int result = 0;
        constexpr int arr[N] = { content... };
        for(std::size_t k = 0; k < N; ++k) {
            result += arr[k];
        }

        return result;
    }
};


template <std::size_t I, int ...A>
constexpr int list_at(list<sizeof...(A),A...>)
{
    if constexpr (I < sizeof...(A))
    {
        constexpr int arr[] {A...};
        return arr[I];
    }
    else
    {
        return 0;
    }
}

template <int ...A, int ...B, std::size_t ...I>
constexpr auto list_sum_low(list<sizeof...(A),A...>,
                            list<sizeof...(B),B...>,
                            std::index_sequence<I...>)
{
    return list<sizeof...(I), (list_at<I>(list<sizeof...(A),A...>{}) +
                               list_at<I>(list<sizeof...(B),B...>{}))...>{};
}

template <int ...A, int ...B>
constexpr auto list_sum(list<sizeof...(A),A...>, list<sizeof...(B),B...>)
{
    constexpr int a = sizeof...(A), b = sizeof...(B);
    return list_sum_low(list<a,A...>{}, list<b,B...>{},
                        std::make_index_sequence<(a > b ? a : b)>{});
}


template <int ...A>
void print_list(list<sizeof...(A),A...>)
{
    (void(std::cout << ' ' << A) , ...);
}


int main()
{
    constexpr auto x = list_sum(list<4, 1,2,3,4>{}, list<2, 10,20>{});
    print_list(x);
}

Also, note that there is no need have size_t N template parameter for class list. Parameter packs know their own size.

Parameter pack(since C++11), A variadic class template can be instantiated with any number of int Tuple<int, float> t2; // Types contains two arguments: int and float� A variadic template is a class or function template that supports an arbitrary number of arguments. This mechanism is especially useful to C++ library developers because you can apply it to both class templates and function templates, and thereby provide a wide range of type-safe and non-trivial functionality and flexibility.

Just another solution, based on good old partial specialization:

template <size_t N, int... E> struct list { };

template <typename, typename> struct list_cat;

template <size_t N1, int... E1, size_t N2, int... E2>
struct list_cat<list<N1, E1...>, list<N2, E2...>>
{ using type = list<N1 + N2, E1..., E2...>; };

template <typename, typename> struct list_add;

template <size_t N1, int E1H, int... E1T, size_t N2, int E2H, int... E2T>
struct list_add<list<N1, E1H, E1T...>, list<N2, E2H, E2T...>>
{
  using type = typename list_cat<
    list<1, E1H + E2H>,
    typename list_add<list<N1 - 1, E1T...>, list<N2 - 1, E2T...>>::type
  >::type;
};

template <size_t N2, int... E2>
struct list_add<list<0>, list<N2, E2...>> { using type = list<N2, E2...>; };

template <size_t N1, int... E1>
struct list_add<list<N1, E1...>, list<0>> { using type = list<N1, E1...>; };

template <>
struct list_add<list<0>, list<0>> { using type = list<0>; }

Which can be used as:

using L1 = list<3, -1, -2, -3>;
using L2 = list <2, 10, 20>;
using L = typename list_add<L1, L2>::type;

Live demo: https://wandbox.org/permlink/x8LYcoC3lWu51Gqo

[PDF] Variadic Templates, 1. 2 A Variadic Templates Primer. 2. 2.1 Variadic Class Templates . typedef tuple<char, short, int, long, long long> integral types; to count, then pack the rest of the arguments into a template parameter pack to be counted in the final sum:. Variadic Template is introduced in C++11. Variadic Template allows a function to take variable number of arguments of any type. Let’s understand by an example. Suppose we want to create a function log() that accepts variable number of arguments of any type and prints them on console i.e.

Another solution std::integer_sequence based.

When the dimension of the two lists is the same, an add() function is trivially simple

template <std::size_t N, int ... Is1, int ... Is2>
constexpr auto add (list<N, Is1...>, list<N, Is2...>)
 { return list<N, Is1+Is2...>{}; }

The problem is when we have lists of different length.

A possible solution is extend the shorter list with zeros and apply the preceding function to the length-uniformed lists.

Given a extender as follows

template <std::size_t N1, std::size_t N0, int ... Is, std::size_t ... Js>
constexpr auto listExtend (list<N0, Is...>, std::index_sequence<Js...>)
 { return list<N1, Is..., ((void)Js, 0)...>{}; }

template <std::size_t N1, std::size_t N0, int ... Is,
          std::enable_if_t<(N1 > N0), bool> = true>
constexpr auto listExtend (list<N0, Is...> l)
 { return listExtend<N1>(l, std::make_index_sequence<N1-N0>{}); }

we need only to add the following add() functions

template <std::size_t N1, int ... Is1, std::size_t N2, int ... Is2,
          std::enable_if_t<(N1 > N2), bool> = true>
constexpr auto add (list<N1, Is1...> l1, list<N2, Is2...> l2)
 { return add(l1, listExtend<N1>(l2)); }

template <std::size_t N1, int ... Is1, std::size_t N2, int ... Is2,
          std::enable_if_t<(N1 < N2), bool> = true>
constexpr auto add (list<N1, Is1...> l1, list<N2, Is2...> l2)
 { return add(listExtend<N2>(l1), l2); }

The following is a full compiling C++14 (unfortunately std::make_index_sequence/std::index_sequence require C++14) example

#include <utility>
#include <type_traits>

template <std::size_t, int ...>
struct list
 { };

template <std::size_t N1, std::size_t N0, int ... Is, std::size_t ... Js>
constexpr auto listExtend (list<N0, Is...>, std::index_sequence<Js...>)
 { return list<N1, Is..., ((void)Js, 0)...>{}; }

template <std::size_t N1, std::size_t N0, int ... Is,
          std::enable_if_t<(N1 > N0), bool> = true>
constexpr auto listExtend (list<N0, Is...> l)
 { return listExtend<N1>(l, std::make_index_sequence<N1-N0>{}); }

template <std::size_t N, int ... Is1, int ... Is2>
constexpr auto add (list<N, Is1...>, list<N, Is2...>)
 { return list<N, Is1+Is2...>{}; }

template <std::size_t N1, int ... Is1, std::size_t N2, int ... Is2,
          std::enable_if_t<(N1 > N2), bool> = true>
constexpr auto add (list<N1, Is1...> l1, list<N2, Is2...> l2)
 { return add(l1, listExtend<N1>(l2)); }

template <std::size_t N1, int ... Is1, std::size_t N2, int ... Is2,
          std::enable_if_t<(N1 < N2), bool> = true>
constexpr auto add (list<N1, Is1...> l1, list<N2, Is2...> l2)
 { return add(listExtend<N2>(l1), l2); }

int main ()
 {
   list<3u, 1, 2, 3> l1;
   list<2u, 10, 20>  l2;

   auto l3 = add(l1, l2);

   static_assert( std::is_same<decltype(l3), list<3u, 11, 22, 3>>::value,
                  "!" );
 }

Variadic template, In computer programming, variadic templates are templates that take a variable number of tuple<int, std::vector<int>, std::map<std::string, std::vector<int>>> type-safe add-on to variadic functions (such as printf), but also allowing a function (If both had the same list of initial parameters, the call would be ambiguous — a� Variadic templates are a C++ feature which looks quite magic the first time you see it. Thanks to C++ Insights, most of the magic disappears. Variadic templates are one of the powerful new constructs we have since C++11. Variadic Templates. They are great because we can have a function that takes multiple arguments and still is strongly typed.

I will use std::integer_sequence:

template <int ... Is>
using int_sequence = std::integer_sequence<int, Is...>;

When size match, it would be easy, so create method to increase size and fill with zero:

template <int... Is, int... Zeros>
int_sequence<Is..., (0 * Zeros)...>
fill_with_zero(int_sequence<Is...>, int_sequence<Zeros...>) { return {}; }

template <std::size_t N, int... Is>
auto fill_with_zero_to_reach(int_sequence<Is...> seq)
-> decltype(fill_with_zero(seq,
                           std::make_integer_sequence<int,
                                                      (sizeof...(Is) < N
                                                       ? N - sizeof...(Is)
                                                       : 0)>{}))
{
    return {};
}

Then the addition:

// simple case, sizes match:
template <int... Is1, int... Is2,
          std::enable_if_t<sizeof...(Is1) == sizeof...(Is2), int> = 0>
int_sequence<(Is1 + Is2)...>
add(int_sequence<Is1...>, int_sequence<Is2...>) { return {}; }

// sizes mismatch:
template <int... Is1, int... Is2,
          std::enable_if_t<sizeof...(Is1) != sizeof...(Is2), int> = 0>
auto
add(int_sequence<Is1...> seq1, int_sequence<Is2...> seq2)
-> decltype(add(fill_with_zero_to_reach<std::max(sizeof...(Is1), sizeof...(Is2))>(seq1),
                fill_with_zero_to_reach<std::max(sizeof...(Is1), sizeof...(Is2))>(seq2)))
{ return {}; }

Demo

Using Variadic Templates cleanly, When one comes across examples for variadic templates, almost always recursion is the tail of the arguments to a list of parameters for the function (see t above). The next problem we will look at, is to calculate the sum of the sums of the const Ts& args) { (void) std::initializer_list<int>{print_to_stream(stream, args). In C programming, variadic function will contribute to the flexibility of the program that you are developing. To understand this flexibility, let us start with a basic example. If we like to add two numbers, we might write a code like this: int addNumbers (int nNumberOne, int nNumberTwo) { return nNumberOne + nNumberTwo; }.

[PDF] Variadic templates, void fi(initializer_list<int>); fi(1);. // error fi({1});. // ok fi({1,2});. // ok fi({{1},{2}});. // ok ? Variadic templates and initializer lists. • List min(): template< typename T, class Compare> const T& add allocators to constructors and assignments. Variadic templates. One of the new features of C++11 is variadic templates.Finally, there's a way to write functions that take an arbitrary number of arguments in a type-safe way and have all the argument handling logic resolved at compile-time, rather than run-time.

#include <tr1/tuple> /** * Object Function Tuple Argument Unpacking * * This recursive template unpacks the tuple parameters into * variadic template arguments until we reach the count of 0 where the function * is called with the correct parameters * * @tparam N Number of tuple arguments to unroll * * @ingroup g_util_tuple */ template < uint N

A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates). A function parameter pack is a function parameter that accepts zero or more function arguments. A template with at least one parameter pack is called a variadic template.

Comments
  • I don't get why it returns an int and not a list<N, int...>
  • Sorry, had a brain fart. Will write an answer in a moment.
  • ot: you dont need the inline. actually I am a bit surprised that it is even allowed in that place
  • How is the reduce function related to your problem?
  • reduce is a red herring; it's a completely different operation. Do you want your result to be a type or a value? You said that it should produce "a new list", but then it's not really a function, if it's supposed to put everything in a type. A value of type list<...> is as good as the type itself.
  • Or we could use the array initialization rules to do the padding. I don't think it gets much simpler than this :-).
  • This is much nicer than the integer_sequence IMHO. I started writing one that was very similar, but had to go out for a while and obviously someone snatched the idea. Good job! :)
  • @BartekBanachewicz That happens to me all the time. People tend to be freakishly quick here on SO ;-)