6

So I have a lambda who's return type is auto and I'm having issues with the array backing for an initializer_list being destroyed here:

const auto foo = [](const auto& a, const auto& b, const auto& c) { return {a, b, c}; };

I will be using the lambda like this:

auto bar = foo(1, 2, 3);

for(const auto& i : bar) cout << i << endl;

A job that I'm working has as part of their coding standard that all lambdas are single statements (feel free to express your outrage.) I think that I can get around this by:

  1. Giving foo a return type of vector int, but that messes up how nicely generic it is: const auto foo = [](const auto& a, const auto& b, const auto& c) -> vector<int> { return {a, b, c}; }
  2. Just writing a templatized function which constructs a vector<T> and returns it: template <typename T> vector<T> foo(const T& a, const T& b, const T& c){ return {a, b, c}; }

Is it possible to coerce these variables into a container, who's backing won't be destroyed all in one line so that I can keep the lambda with an auto return type?

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 1
    It's not an `initializer_list`, it's an initializer list. Two different things. There's nothing for it to be deduced to, hence why it fails. – uh oh somebody needs a pupper Jun 06 '16 at 11:34
  • 1
    How about packing the return in lambda as tuple and unpacking them into a container as initializer_list ? – Arunmu Jun 06 '16 at 11:38
  • What do want to have happen if `a`, `b`, and `c` have different types? – NathanOliver Jun 06 '16 at 11:39
  • @sleeptightpupper I'm not certain what you mean by this comment? Perhaps you are spelling out the solution for me, and I don't get it. What do you mean that this isn't an `initializer_list`? What type is my lambda returning here? – Jonathan Mee Jun 06 '16 at 12:02
  • @Arunmu Believe it or not that's one of the things I'd tried. But in the end if just is way more pointless busy work than just doing **2** :( – Jonathan Mee Jun 06 '16 at 12:03
  • @NathanOliver It wouldn't compile? Perhaps your indicating that I should just give up the `auto` parameters in `foo` and just use `int`, thereby also freeing me to use **1**? Not a bad suggestion certainly, that may be as good a solution as there is. – Jonathan Mee Jun 06 '16 at 12:06
  • @JonathanMee Agreed, that would be bit too much of work. – Arunmu Jun 06 '16 at 12:23
  • 1
    This shouldn't even compile as-is. There's a rule against a deduced return type mixed with braced initializer lists in `return` precisely so that you don't mess things up. – T.C. Jun 06 '16 at 12:26
  • @sleeptightpupper You put together an excellent answer here, and I'm sad to see that you've deleted it. But perhaps you can dump some of that information into an answer on this question: http://stackoverflow.com/q/37682392/2642059 – Jonathan Mee Jun 07 '16 at 14:41

1 Answers1

3

The library fundamentals TS v2 has std::experimental::make_array, which would certainly satisfy your requirements:

#include <experimental/array>
const auto foo = [](const auto& a, const auto& b, const auto& c) {
    return std::experimental::make_array(a, b, c); };

More generally, template argument deduction for constructors would allow you to write:

const auto foo = [](const auto& a, const auto& b, const auto& c) {
    return std::vector{a, b, c}; };
                      ^-- no template parameter required

Today, you could emulate this using common_type:

const auto foo = [](const auto& a, const auto& b, const auto& c) {
    return std::vector<std::common_type_t<decltype(a), decltype(b), decltype(c)>>{a, b, c}; };
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • 1
    Oh snap! I didn't know that I could declare a `vector` without specifying type! – Jonathan Mee Jun 06 '16 at 12:26
  • 1
    @JonathanMee you can't *yet*, but there's hope you will be able to in C++17. – ecatmur Jun 06 '16 at 12:27
  • 1
    Couldn't you just write `std::vector{a, b, c}`? (Looks like that was kind of added as an answer after I wrote that) – KABoissonneault Jun 06 '16 at 12:30
  • @KABoissonneault absolutely; note that here `std::common_type` does the work of removing reference and cv qualifiers, as it calls `std::decay` on its result (since C++14). – ecatmur Jun 06 '16 at 12:39