-1

The code I want to work

#include <iostream>

using namespace std;

int main()
{
    int v = 123;
    
    auto doFn = [v](){ cout << "Hello World" << v << "\n"; };
    auto noopFn = [v](){};

    for (int i = 0; i < 4; ++i)
    {
        auto fn = (i & 1) ? doFn : noopFn;
        fn();
    }

    return 0;
}

The error I get

main.cpp:14:27: error: operands to ?: have different types ‘main()::’ and ‘main()::’
   14 |         auto fn = (i & 1) ? doFn : noopFn;
      |                   ~~~~~~~~^~~~~~~~~~~~~~~

I found this answer but if it's a solution I don't understand how to apply it.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
samanthaj
  • 521
  • 3
  • 14
  • 5
    Wrap the closures with `std::function` – The Dreams Wind Sep 09 '22 at 22:09
  • @JeJo, because I have 50 lambdas, not just 2 – samanthaj Sep 10 '22 at 00:30
  • @samanthaj *"because I have 50 lambdas,"* -- I find it hard to see how this is more of a problem for using an `if` statement than for using the ternary operator. E.g.: ternary operator: `fn = (condition1) ? doFn1 : (condition2) ? doFn2 : noopFn; fn();` vs. statement: `if (condition1) doFn1(); else if (condition2) doFn2();` (no need for a no-op in a final `else`). *Maybe you have over-simplified?* – JaMiT Sep 10 '22 at 00:42
  • I notice comments shooting down ideas that fit the question as asked. This is often a sign that the question does not ask what it was intended to ask. This is a common problem for questions that rely on code instead of words to communicate the situation. And, indeed, the entire textual description of your scenario is the word "this", referring to your code. Your question would probably benefit from more text before you demonstrate your scenario with code. – JaMiT Sep 10 '22 at 00:48
  • I didn't ask how I can execute one function over another. I asked how I can get two functions to match on type. If you're answering the question of how to execute one function or another that's not the question that was asked. The code is the shortest example I could think of to show wanting the types to match. both functions need to be assignable to `fn` – samanthaj Sep 10 '22 at 00:58
  • Every lambda has a unique type. – n. m. could be an AI Sep 10 '22 at 06:30
  • @samanthaj *"I didn't ask how I can execute one function over another."* -- True, but only because you did not actually ask anything. If we go by the implied question ("The code I want to work"), then we look at the code you want to work, and we see that it immediately executes `fn` after assigning it a value. If you don't like people drawing inferences and making assumptions from your code, then **don't rely on your code to ask your question for you**. Use your words to explain what you mean. See also [ask]. – JaMiT Sep 10 '22 at 12:12

3 Answers3

2

Change the lambdas the following way

auto doFn = []( const int &v){ std::cout << "Hello World" << v << "\n"; };
auto noopFn = []( const int &v){};

for (int i = 0; i < 4; ++i)
{
    auto fn = (i & 1) ? doFn : noopFn;
    fn(v);
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • my C++ fu is low but I find it interesting that `[v](void){}` and `[v](void}{ cout << v;}` don't match but passing in a parameter fixes that. – samanthaj Sep 10 '22 at 01:00
  • @samanthaj The reason for that is, that a stateless lambda can decay to a function pointer, which is not possible for a stateful lambda. – gerum Sep 10 '22 at 07:03
1

The lambda (fast way):

int main()
{
    int v = 123;
    
    auto doFn = [v](){ cout << "Hello World" << v << "\n"; };
    auto noopFn = [v](){};

    for (int i = 0; i < 4; ++i)
    {
        auto fn = [=] { i & 1 ? doFn() : noopFn(); };
        fn();
    }

    return 0;
}

The std::function (slow way):

int main()
{
    int v = 123;
    
    auto doFn = [v](){ std::cout << "Hello World" << v << "\n"; };
    auto noopFn = [v](){};

    for (int i = 0; i < 4; ++i)
    {
        auto fn =  i & 1 ? std::function{doFn} : noopFn;
        fn();
    }

    return 0;
}
bolov
  • 72,283
  • 15
  • 145
  • 224
  • This is a creative solution but it's not very generic. If I had lots more functions to choose from that extra lambda would get pretty hairy :P – samanthaj Sep 09 '22 at 22:14
  • @samanthaj why hairy ? not more than the if-else to select the lambda to be assigned to the `std::function`. Actually it is exactly the same – 463035818_is_not_an_ai Sep 09 '22 at 22:17
0

As @TheDreamsWind pointed out

Wrap the closures with std::function

#include <iostream>
#include <functional>

using namespace std;

int main()
{
    int v = 123;
    
    auto doFn = std::function<void()>([v](){ cout << "Hello World" << v << "\n"; });
    auto noopFn = std::function<void()>([v](){});

    for (int i = 0; i < 4; ++i)
    {
        auto fn = (i & 1) ? doFn : noopFn;
        fn();
    }

    return 0;
}
samanthaj
  • 521
  • 3
  • 14
  • 2
    In this case, I would drop `auto` on the lambdas and make those variable types explicit, eg: `std::function doFn = [v](){ cout << "Hello World" << v << "\n"; }; std::function noopFn = [v](){};`, it is a little more readable, I think. – Remy Lebeau Sep 09 '22 at 22:25