通过移动在同一语句中使用的变量来捕获

时间:2018-01-09 09:48:23

标签: c++ gcc lambda c++14 move-semantics

编辑:标记为重复(有点,没有未定义的行为,只是未指定),我被移动的lambda捕获的人为复杂性所欺骗,这是无关紧要的。

我的同事和我发现GCC 6,7和Clang之间存在奇怪的差异,当我们尝试通过在之后移动来获取变量时,在同一语句中使用const引用。 一个最小的例子:

LoggingAdapter.process()

Wandbox链接:https://wandbox.org/permlink/TMoB6EQ7RxTJrxjm

GCC 6.3中的输出:

#include <iostream>
#include <string>

struct A
{
    template <class F> void call (F f)
    {
         f();
    }
};

A test(const std::string& s)
{
    std::cout << "in method: " << s << std::endl;
    return {};
}

int main()
{
    std::string s = "hello";
    test(s).call([s = std::move(s)] { std::cout << "in lambda: " << s << std::endl;});
    return 0;
}

GCC 7.2和Clang中的输出:

in method: 
in lambda: hello

请注意,使用两个语句,即in method: hello in lambda: hello ,可以得到与GCC 6.3相同的(第二个)结果。我们天真地期待到处都是第二个输出:它是GCC 6错误,未定义的行为还是标准的变化?

有关信息,我们的“真实”情况是异步调用:auto t = test(s); t.call(...);是调用,test是期​​望回调的结果。

1 个答案:

答案 0 :(得分:3)

在C ++ 14中,未指定是先评估test(s)还是先评估lambda表达式。但是,没有未定义的行为(假设test没有触发UB与移动的string)。

在C ++ 17中,test(s)始终在lambda之前进行评估。