Search code examples
c++c++17variadic-templatesinitializer-listargument-unpacking

Unpack variadic template to initializer_list and call two functions at once


I have two vectors:

std::vector<int> v1{ 1, 2, 3 };
std::vector<int> v2{ 4, 5, 6 };

I want to create an object of std::initializer_list which holds iterators to the first and last elements of above vectors.

I want to have a function with a variadic template:

template<class... Ts>
void foo(Ts... args)

and inside above function I want to unpack all arguments. So far I implemented:

template<class... Ts>
void foo(Ts... args)
{
  std::initializer_list<std::vector<int>::iterator> il{
    (std::begin(args), std::end(args))...
  };
}

int main()
{
  std::vector<int> v1{ 1, 2, 3 };
  std::vector<int> v2{ 4, 5, 6 };

  foo(v1, v2);
}

but it doesn't work as expected due to operator,. Current implementation creates initializer_list with two iterators. What I want in this case is to have an initializer_list with 4 iterators pointing to the first and one past the end element of these two vectors. I want it to be begin, end, begin, end.


Solution

  • You can make a new pack which is double the length:

    #include <vector>
    #include <utility>
    #include <tuple>
    
    namespace detail {
    
    template<std::size_t... I, class... Ts>
    void foo_impl(std::index_sequence<I...>, Ts&... args) {
        std::initializer_list<std::vector<int>::iterator> il{
            [&]() -> std::vector<int>::iterator {
                auto& vec = std::get<I/2u>(std::tie(args...));
                return I % 2u == 0u ? std::begin(vec) : std::end(vec);
            }()...
        };
    
        // ...
    }
    
    }
    
    template<class... Ts>
    void foo(Ts... args) {
        return detail::foo_impl(std::make_index_sequence<sizeof...(args)*2u>{}, args...);
    }
    

    Or consider if you need an initializer_list at all. You might be able to use an array:

    template<class... Ts>
    void foo(Ts... args) {
        std::vector<int>::iterator il[sizeof...(args)*2u];
        {
            auto* p = std::begin(il);
            (((*p++ = std::begin(args)), (*p++ = std::end(args))), ...);
        }
    
        // ...
    }