This works, but would have failed had there been two elements of type std::string in the tuple.

Note
how we had to write the type of threeElems in the last example. If we
had used auto instead, its type would be deduced as std::tuple
<int, char const*, double>
because std::make_shared deduces the type of
the returned tuple using the types of the passed arguments. If you
wanted to use a string literal whose type would be deduced as
std::string, you must use an s suffix like this:

The
key is the use of the auto keyword for the parameter types. You could
use multiple parameters, all declared auto, whose types are
independently deduced. How does this really help? First, you don't have to write:

[](Foo& elem) { std::cout << elem << '\n'; }

Also, you could cache a lambda in a generic context with minimal syntactic noise and reuse it for multiple types. Consider this: