Question

In this example, is it possible to allow the deduction of the template parameters type of the tuple?

#include<tuple>
#include<string>

template<class T1, class T2>
void fun(std::tuple<T1, T2> t, std::string other){}

int main(){
    fun(std::tuple<double, int>(2.,3), std::string("other")); // ok
    fun(std::make_tuple(2.,3), std::string("other")); // ok, but trying to avoid `make_tuple`
    fun({2.,3},std::string("other")); // desired syntax but
    // giving compilation error: candidate template ignored: couldn't infer template argument 'T1' void fun(std::tuple<T1, T2> t)
}

I added the second argument other to avoid solutions involving variadic arguments at the level of the function fun. Also, I am trying to avoid the use of make_tuple, at least from the user code (i.e. in main()). In fact it doesn't need to be the tuple type the one involved as long as the "desired syntax" is allowed and somehow its element types can be deduced at later stage.

(Also, although similar, this has nothing to do with initializer_list since it doesn't work at all having dissimilar elements in the braces)

It fails at least with clang 3.2 and gcc 4.7.2. Is there any hope that it would work with the current or a near-future standard? (e.g. a future(?) initializer_tuple.)

(This can be very useful to add expressiveness to function calls, by aggregating subelements, but that can be argued about)


Note: For the example code it seems that std::forward_as_tuple is more appropriate than std::make_tuple so the arguments are not necessarily copied: http://en.cppreference.com/w/cpp/utility/tuple/forward_as_tuple . Still not as nice as if there were a build-in language feature for heterogeneous initializer lists.

Was it helpful?

Solution

No, there is absolutely no way. Deduction fails if the element types are not of the same type. And no deduction is done at all if the parameter is not a std::initializer_list<T> anyway (you are right that initializer_list doesn't have anything to do with the braces you give, but this is the simple rule for deduction to work).

The template parameter values must be deduced by other function parameter positions involving them or must be explicitly specified.

OTHER TIPS

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top