Build tuple from heterogeneous initializer list at function call
Asked Answered
D

2

17

Consider the following function

template <class... T, class... U>
void f(std::tuple<T...> t, std::tuple<U...> u)
{
    std::cout << sizeof...(T) << " " << sizeof...(U) << std::endl;
}

int main(int argc, char* argv[]) 
{
    f({3, 3.5, "Hello World!"}, {'a', std::string("b")}); // Fails
    return 0;
}

Would there be any way in C++17 to modify the function signature so that the line marked "Fails" would work? (keeping that line the same).

Dissonance answered 5/6, 2017 at 4:41 Comment(0)
H
12

My guess is that the short answer is no.
Roughly speaking, { args... } isn't a tuple and you incur in the same deduction and conversion issues you were facing in C++14.


That being said, in C++14/17 you can do this to simulate it (minimal, working example):

#include<iostream>
#include<string>
#include<tuple>
#include<utility>

template <class... T, class... U>
void f_(std::tuple<T...> t, std::tuple<U...> u) {
    std::cout << sizeof...(T) << " " << sizeof...(U) << std::endl;
}

template<typename... T>
auto f(T... t) {
    return [tup{std::make_tuple(t...)}](auto... u) {
        f_(std::move(tup), std::make_tuple(u...));
    };
}

int main(int argc, char* argv[]) {
    f(3, 3.5, "Hello World!")('a', std::string("b"));
    return 0;
}

Generic lambdas do the magic for you and you have something similar to what you want with an extra level of indirection (that usually helps to solve any problem).


In C++17 you can also do this:

f(std::tuple{3, 3.5, "Hello World!"}, std::tuple{'a', std::string("b")});

That is having types of arguments deduced directly from the call to the constructor instead of explicitly specifying them. With an alias you can even go further and reduce the expressions at the call point to something like this:

f(T{3, 3.5, "Hello World!"}, T{'a', std::string("b")});

Anyway you sacrifice readability for that and it doesn't worth it from my point of view.

Helainehelali answered 5/6, 2017 at 6:26 Comment(0)
F
7

In C++17, you might write:

f(std::tuple{3, 3.5, "Hello World!"}, std::tuple{'a', std::string("b")});

Prior, you may use std::make_tuple:

f(std::make_tuple(3, 3.5, "Hello World!"), std::make_tuple('a', std::string("b")));

but nothing to let the line unmodified and keeping the function template.

Fetiparous answered 5/6, 2017 at 7:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.