0

EDIT: added the compiler errors at the end. First I'll say I have both Visual Studio Express 2013 and CodeBlocks (Mingw w64) set up and running. But I am having a problem with some code compiling with one compiler but not the other and vis-versa.

Consider this code:

void foo(std::string& s){
    std::cout << "in foo function now" << std::endl;
    s = "the new string.";
}

int main(){
    std::string s = "the original string";
    std::thread t1(foo, std::ref(s));
    t1.join();

    if (!s.size()) std::cout << "s is empty" << std::endl;
    else std::cout << s << std::endl;

    std::cin.get();
    return 0;
}

It compiles and runs fine on both GCC and VS.

BUT if I decide to change std::ref(s) with std::move(s) it won't compile with GCC anymore but it will with VS. To fix it I have to add a '&' so void foo(std::string& s) becomes void foo(std::string&& s), THEN it will compile with gcc but it won't with VS anymore!

My guess would be that the VS compiler is quiet forgiving and is not following the standard to the letter but I haven't withness such a behavior with std::function and std::bind even though the arguments are passed the same way I believe.

At any rate I would very much appreciate some help in understanding what is going on.

EDIT: The errors: The GCC one:

C:/mingw-w64/x86_64-5.1.0-posix-seh-rt_v4-rev0/mingw64/x86_64-w64-mingw32/include/c++/functional:1505:61: error: no type named 'type' in 'class std::result_of<void (*(std::__cxx11::basic_string<char>))(std::__cxx11::basic_string<char>&)>'
       typedef typename result_of<_Callable(_Args...)>::type result_type;
                                                             ^
C:/mingw-w64/x86_64-5.1.0-posix-seh-rt_v4-rev0/mingw64/x86_64-w64-mingw32/include/c++/functional:1526:9: error: no type named 'type' in 'class std::result_of<void (*(std::__cxx11::basic_string<char>))(std::__cxx11::basic_string<char>&)>'
         _M_invoke(_Index_tuple<_Indices...>)

The VS one:

Error   1   error C2664: 'void (std::string &&)' : cannot convert argument 1 from 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' to 'std::string &&' c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional   1149    1   Tests
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Ark.
  • 81
  • 1
  • 4
  • 1
    Quote compiler errors explicitly. Could be related: [std::thread constructor doesn't handle movable object](https://connect.microsoft.com/VisualStudio/feedback/details/729886) – Ivan Aksamentov - Drop Aug 15 '15 at 17:32
  • 1
    possible duplicate of [Can't invoke or assign a std::function that has an rvalue reference as an argument (Visual C++)](http://stackoverflow.com/questions/16155395/cant-invoke-or-assign-a-stdfunction-that-has-an-rvalue-reference-as-an-argume) – Rudolfs Bundulis Aug 15 '15 at 17:44
  • `foo(std::move(s))` shouldn't compile either. A mutable reference won't bind to an rvalue expression. So `std::move`ing the argument into the `std::thread` constructor is not something expected to work. – 5gon12eder Aug 15 '15 at 18:03

1 Answers1

1

MSVC is wrong, both under the standard and practically.

Internally, they both copy the arguments into something tuple-like, the unpack them in the spawned thread and a call is made.

Under the standard, the invoke expression must pass the values as rvalues into the called function after copying them (well, except for std::ref cases).

This is because of the wording of the INVOKE clause in this standard. I've talked about it before here, but have not tracked it down yet.

Logically, the value in the tuple is never going to be used again, so it should be in an rvalue context not an lvalue one. Taking something by value, copying it, then passing it by reference, then throwing out the copy, is usually a bug.

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • The thing is `function f1 = bind(f, move(s));` with `void f(string& s)` definition works and compiles just fine under GCC even though it has the same syntax as with `std::thread.` This is very confusing to me. – Ark. Aug 15 '15 at 21:09
  • @ark thread is call-once, `bind` is (possibly) call-many. The value of the string is discarded under call-once. And `bind` and thread have different meanings in the standard. I am not fluent in `bind` as I find it obsolete currently. – Yakk - Adam Nevraumont Aug 15 '15 at 23:57