5

Lets say I have the following code snippets:

// global variable
std::thread worker_thread;

// Template function
template <typename Functor>
void start_work(Functor &worker_fn)  // lambda passed by ref
{
    worker_thread = std::thread([&](){
        worker_fn();
    });
}

This is called like this:

void do_work(int value)
{
    printf("Hello from worker\r\n");
}

int main()
{
    // This lambda is a temporary variable...
    start_work([do_work](int value){ do_work(value) });
}

I started developing on MSVC2012. This all compiled up fine and seemed to work. However when I moved onto the gcc compiler on Linux platform I got the following (abbreviated) error:

no known conversion for argument 1 '...__lambda3' to '...__lambda3&'

My Questions:

  • So, from the error I assume that the lambda was a temporary variable and it therefore can't be passed by reference - is that right?
  • Also - any idea why this would work with MSVC? - is it auto-fixing what I wrote?
Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
code_fodder
  • 15,263
  • 17
  • 90
  • 167

1 Answers1

7

MSVC deviates from the standard in that it allows anonymous temporaries to be bound to non-const lvalue references. You can switch this off using the /Za compiler flag ("disable language extensions"), or the sharper /permissive- option from MSVC2017.

The C++ standard has always been clear that anonymous temporaries can only bind to const references.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • Ah, cool - so I "fixed" my code by removing the "by-ref" (i.e. by copy) so in theory I can still pass by ref as long is its `void start_work(const Functor &worker_fn) ` - is that the correct signature? – code_fodder Apr 23 '18 at 12:52
  • @code_fodder; yup, using `const` reference for the function parameter will fix the gcc build. – Bathsheba Apr 23 '18 at 12:53
  • sweet, thanks dude : ) ... have to wait 8 mins to mark up answer... : ( – code_fodder Apr 23 '18 at 12:54
  • 1
    Made a tiny pedantic correction. Hope you don't mind – StoryTeller - Unslander Monica Apr 23 '18 at 12:56
  • @StoryTeller: not at all. Thank you very much! – Bathsheba Apr 23 '18 at 12:57
  • One note: (probably due to my lack of visual studio know-how) if I use /Za my project blows up! (get loads of errors in things like winnt.h and so on.. so I am guessing that this comes with a shed full of caveats (or is probably another question entirely)... so I'll leave that option alone for now! : ) – code_fodder Apr 23 '18 at 12:59
  • Just had a thought - do I have an "out of scope issue here" since the lambda is temporary? – code_fodder Apr 23 '18 at 13:24
  • 1
    No, it will be kept in scope for the duration of the function call. – Bathsheba Apr 23 '18 at 13:25
  • Even with the thread? because the function will return and the thread still running...lambda passed to lambda.... my head hurts at this point? – code_fodder Apr 23 '18 at 13:26
  • No, the rules for lambda capture are similar for those that can contrive a dangling reference. This is a question in itself which I know @StoryTeller will jump on. – Bathsheba Apr 23 '18 at 13:30
  • @Bathsheba sorry, do you mean "no" to "do I have an out of scope issue?" or "no" to "Even with the thread?" (i.e. yes in this case you will have an out of scope issue? ... as you say, any further info is another question (which I will probably ask if I can't find the answer already! : ) – code_fodder Apr 23 '18 at 13:36
  • 1
    @code_fodder: The "even with the thread". You need to make sure that the original object is in scope if you are using a reference in a lambda capture, at the point the lambda runs. – Bathsheba Apr 23 '18 at 13:37
  • @Bathsheba awesome thanks very much for taking the time : ) – code_fodder Apr 23 '18 at 13:38