2

Based on: How do I expand a tuple into variadic template function's arguments?

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

template <typename... Args>
void print_all(const Args &... args) {
    ((std::cout << " " << args), ...) << std::endl;
}

int main()
{

    // Create a tuple
    auto values = std::make_tuple(1, 2, 3.4f, 4.5, "bob");
    
    // Need to pass the tuple through the lambda for template type deduction and to pass param to template function?
    std::apply([](auto &&... args) { print_all(args...); }, values);

    // This does not work - other then there is no parameter I can't see how this does not work
    // and how the lambda does work as it has the same (roughly) param list
    std::apply(print_all(), values);


    return 0;
}

can someone explain why one works and the other does not?

code_fodder
  • 15,263
  • 17
  • 90
  • 167
  • 1
    `print_all()` is a function call but you don't want to call the function - you want to pass it. It does work (with the right syntax): [**Demo on coliru**](http://coliru.stacked-crooked.com/a/7be9b2eb49eb11e7). Though, type deduction doesn't seem to be an option here. – Scheff's Cat Dec 17 '20 at 13:43
  • 1
    the pointers of these instances of a function template are different values, so compiler doesn't know what `print_all` should be decayed to. whether function template or overloaded function is not mono-state, you have to wrap it with a functor or a lambda, to give the argument a definite type. – RedFog Dec 17 '20 at 13:52
  • @Scheff thnks for that - that makes sense to me, but (hopefully obviously) I don't want to pass all the template types! :) – code_fodder Dec 17 '20 at 14:01
  • @RedFog I think I get that bit - what I was struggling with is how the lambda works given it has the same param list -but as the answer below points out its more like an operator() template overload then a function template (If I understood correctly) – code_fodder Dec 17 '20 at 14:02

1 Answers1

4

Behind the scences, this lambda expression [](auto &&... args) { print_all(args...); } is roughly of type:

 struct [unnamed] {
      template <typename ...Args>
      void operator()(Args&&...args) { ... };
 };

It is a type with a templated operator(), ie overload resolution and template argument dedcution only take place once the operator() is actually called. print_all on the other hand is a template, hence you cannot pass it to std::apply.

In other words, no matter what Args... is, the lambda is always of same type, but print_all isn't. You would need to instantiate it before you can get a pointer to the function. As mentioned by Scheff, this is fine:

std::apply(&print_all<int, int, float, double, const char*>, values);
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • oh I see.... so if I made a struct (like you did) with a template operator() then it will work - hence using a lambda is a nice trick to get around that - got you thanks! – code_fodder Dec 17 '20 at 14:00