It is the age of C++20 and there is still no general way to do this.
Workaround 1:
There is a partial solution in the case that the bracket syntax it is, for any reason, reserved for a particular combination of arguments: for example
template<class T1 = double, class T2 = int>
void fun(std::tuple<T1, T2> t, std::string other){}
int main(){
fun({2.,3},std::string("other")); // now works at least, but it may not mean what it seems
}
https://godbolt.org/z/xGaEP5EGn
The worst part of this solution is that it lets exchange the double and the int, but I would say that is a problem of the implicit conversions of built-in types.
It works for any version of C++.
Workaround 2:
The only change since the OP is that now there is CTAD (class template argument deduction).
Which means that there is a new partial workaround for this problem, which is
fun(std::tuple{2.,3}, std::string("other")); // ok, but still trying to avoid `tuple`
Fantasy solution:
This inspired me to think that may be this can be done if CTAD is extended in the future with one of these syntax:
The natural extension to CTAD is if this worked:
void fun(std::tuple t, std::string other){} // implicitly a template because std::tuple is a template
More explicitly:
void fun(std::tuple<auto, auto> t, std::string other){} // implicitly a template because std::tuple is a template and `auto`.
or
template<template<typename...> class Tuple = std::tuple>
void fun(Tuple t, std::string other){}
or
template<template<typename...> class Tuple = std::tuple, class T1, class T2>
void fun(Tuple<T1, T2> t, std::string other){}
None of these work currently, but I am fond of the first and the last option.
The first because it is an extension of CTAD (the type is moved from the calling point to the function argument).
Besides CTAD has been shown to work with (non deduced) template template classes.
The last because it is template argument deduction, under some expanded definition of deduction.
The default argument can help deduce the template template argument (std::tuple
).