16

I am trying to add two c++ lambda-funtions. What I mean by that is the following:

Assume you have two functions f and g with one or more arguments each, lets say f(x,y) and g(x,y). I want to add both of them into a new function h like this:

h = f + g

And the evaluation should work like this:

h(x,y) = f(x,y) + g(x,y)

So far I have tried the following code, but it does not work. The "cin" at the end is just there to prevent the console from closing automatically.

#include <iostream>
#include <functional>

using namespace std;


function<int (int,int)> add(function<int(int, int)> g, function<int(int, int)> f)
{
    return [&](int x, int y)->int{return g(x, y) + f(x, y); };
}


int main()
{
    int i = 0;

    function<int (int,int)> sum = [](int x, int y)->int { return x + y; };
    function<int (int,int)> mul = [](int x, int y)->int { return x * y; };
    cout << sum(1, 2) << endl;
    cout << mul(3, 4) << endl;

    function<int(int, int)> s = add(sum, mul);

    cout << s(2, 3) << endl;

    cin >> i;
}

The code compiles but it stops working when I try to evaluate s(2,3). It just says the programm stopped working and I have to close it. I am using Visual Studio 2013.

Does anyone know how to do this right? Or do you know any libraries that can do this out of the box?

Rohit.007
  • 3,414
  • 2
  • 21
  • 33
pbit24
  • 418
  • 4
  • 12
  • 2
    [c++ - C++11 Lambda closure involving a stack variable by reference that leaves scope is allowed but getting undefined behavior? - Stack Overflow](https://stackoverflow.com/questions/12463269/c11-lambda-closure-involving-a-stack-variable-by-reference-that-leaves-scope-i) – user202729 Jun 01 '19 at 08:26
  • 8
    Note: `std::function` ain't a lambda, it wraps a lambda with a performance cost. – JVApen Jun 01 '19 at 10:54
  • Related: https://stackoverflow.com/q/6441218 – L. F. Jun 02 '19 at 03:15

1 Answers1

33

It's subtle.

function<int (int,int)> add(function<int(int, int)> g, function<int(int, int)> f)
{
    return [&](int x, int y)->int{return g(x, y) + f(x, y); };
         // ^-- This here
}

You capture g and f by reference, and store those references in the std::function you return. But those are references to a function's local variables, so they dangle the second you return. Your code therefore simply has undefined behavior.

A simple fix would be to capture by value [=].

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • I personally always specify which numbers I capture: it may prevent you from making some mistakes. For me, it is same as strong typing. – val - disappointed in SE Jun 01 '19 at 18:10
  • 2
    Would capturing by reference work correctly if the function parameters were declared as references? e.g. `add(function<> &g, function<> &f)`? – ApproachingDarknessFish Jun 02 '19 at 01:07
  • 3
    @ApproachingDarknessFish - Correctly in the immediate calling context. Those references can still dangle. And since those aren't const lvalue references, now passing a lambda in has become more cumbersome. I'm not a fan of absolute statements, but in the case of a long lived `std::function`, capturing by value is the sensible default thing to do. – StoryTeller - Unslander Monica Jun 02 '19 at 05:20