Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>There's no need to explicitly specify the result of map, it can be deduced. I'm also going to accept any range (something that provides begin and end), simply because doing so is trivial. I could make it even more generic and use the free begin and end versions, but that makes it even more complicated, so I won't.</p> <pre><code>template &lt;typename Range, typename Func&gt; auto map(const Range&amp; r, Func f) -&gt; std::vector&lt;typename std::decay&lt;decltype(f(*r.begin()))&gt;::type&gt; { std::vector&lt;typename std::decay&lt;decltype(f(*r.begin()))&gt;::type&gt; result; for (const auto&amp; e : r) { result.push_back(f(e)); } // Alternatively: //std::transform(r.begin(), r.end(), std::back_inserter(result), f); return result; } </code></pre> <p>This isn't exactly trivial code, so let me explain.</p> <p>First, I use the late-specified return type syntax here: I start the function with <code>auto</code> and put the actual return type after the parameters, indicated with <code>-&gt;</code>. This allows me to use parameter names in the return type specification, which is very useful in the <code>decltype</code> stuff I'm doing next.</p> <p>So what do we actually want? We want a vector of whatever <code>f</code> returns when called with elements of <code>r</code>. What is that? Well, we can use <code>decltype</code> to find out. <code>decltype(expr)</code> gives you the type of <code>expr</code>. In this case, the expression is a call to <code>f</code>: <code>decltype(f(arguments))</code>. We have one argument: an element of the range. The only things a range gives us are <code>begin()</code> and <code>end()</code>, so let's use that: dereference <code>begin()</code> to get the actual value. The expression is now <code>decltype(f(*r.begin()))</code>. Note that this is never actually evaluated, so it doesn't matter if the range is empty.</p> <p>Ok, this gives us the return type of the function. But if we write <code>std::vector&lt;decltype(...)&gt;</code> that leaves us with a problem: the return type of the function could be a reference, but a vector of references is not valid. So we apply the <code>std::decay</code> metafunction to the return type, which removes references and cv-qualifiers on the referenced type, so if the function returns <code>const Foo&amp;</code>, the result of <code>std::decay</code> is just <code>Foo</code>.</p> <p>This leaves me with the final return type <code>std::vector&lt;typename std::decay&lt;decltype(f(*r.begin()))&gt;::type&gt;</code>.</p> <p>And then you get to repeat the same thing to declare the actual variable holding the return value. Unfortunately, because there's no way to put type aliases at any reasonable point, you can't get rid of this.</p> <hr> <p>Anyway, there was another problem with your original code, and that was declaring the loop variable as <code>auto</code>. If you call this <code>map</code> with a <code>vector&lt;Bar&gt;</code>, you end up with the loop</p> <pre><code>for (Bar b : in) { ... } </code></pre> <p>Notice how your loop variable is a value? This means that you copy every element of <code>in</code> to a local variable. If a <code>Bar</code> is expensive to copy, this is a serious performance issue. And if your transformation relies on the object identity of its argument (e.g. you return a pointer to a member), then your performance issue has become a <em>correctness issue</em>, because the resulting vector is full of dangling pointers. This is why you should use <code>const auto&amp;</code> in the loop, or just use the <code>std::transform</code> algorithm internally, which gets this right.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload