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.