GCC-Visual Studio std::线程编译器的差异

GCC-Visual Studio std::thread compiler differences

本文关键字:编译器 线程 Studio std GCC-Visual      更新时间:2023-10-16

编辑:在末尾添加了编译错误。首先,我会说我已经设置并运行了Visual Studio Express 2013和CodeBlocks (Mingw w64)。但我有一个问题,一些代码编译与一个编译器,但不是另一个,反之亦然。

考虑以下代码:

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;
}

在GCC和vs上都能很好地编译和运行。

但是如果我决定用std::move(s)改变std::ref(s),它将不再与GCC编译,但它将与VS。为了修复它,我必须添加一个'&',所以void foo(std::string& s)变成void foo(std::string&& s),然后它将与gcc编译,但它不会与VS了!

我的猜测是VS编译器是安静宽容的,并没有严格遵循标准,但我还没有看到std::function和std::bind有这样的行为,尽管我相信它们的参数传递方式相同。

无论如何,如果你能帮助我了解这是怎么回事,我将非常感激。

编辑:错误:GCC版本:

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...>)

VS:

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.0vcincludefunctional   1149    1   Tests

MSVC是错误的,既不符合标准,也不符合实际。

在内部,它们都将参数复制到类似tuple的东西中,在派生线程中解包它们并进行调用。

在标准下,调用表达式必须在复制后将值作为右值传递给被调用函数(好吧,除了std::ref的情况)。

这是因为本标准中INVOKE条款的措辞。我以前在这里说过,但是还没有找到。

逻辑上,tuple中的值永远不会再被使用,所以它应该在右值上下文中,而不是左值上下文中。按值获取某物,复制它,然后通过引用传递它,然后抛出副本,这通常是一个bug。