C++ std::bind在作为右值引用交付时丢失引用

C++ std::bind在作为右值引用交付时丢失引用,c++,stdbind,C++,Stdbind,我有以下代码: #include <stdio.h> #include <functional> template <typename T> auto callback(T&& func) ->decltype(func()) { return func(); } double test(double& value) { value=value+1.0; return value; } int mai

我有以下代码:

#include <stdio.h>
#include <functional>

template <typename T>
auto callback(T&& func) ->decltype(func())
{
    return func();
}

double test(double& value)
{
    value=value+1.0;
    return value;
}

int main(void)
{
    double t=1.0;
    printf("%f\n",t);
    test(t);
    printf("%f\n",t);
    callback(std::bind(test,t));
    printf("%f\n",t);
}
这意味着
回调
函数获得了
t
的副本,而不是对
t
的引用。我想知道发生了什么,因为对于
std::bind
来说,它应该是完美的转发。

std::bind()
是为值语义()设计的,并且在内部创建副本。您需要/想要的是:

std::ref
返回一个对象,该对象包装对原始参数的引用。这样,将复制
t
周围的
reference\u包装
对象,而不是
t
本身

这允许您在值语义(默认情况下假定)和引用语义(需要显式干预)之间进行选择


下面是一个示例。

std::bind
默认使用值语义。这是一个明智的默认设置,允许您安全地执行以下操作

int f(double x);

auto fun = std::bind(f, 1.0); // stores a copy, not a reference to a temporary
fun();
使用值语义是安全的:绑定参数的生存期成为绑定返回的对象的生存期。使用引用语义并不能保证这一点。因此,当需要引用语义时,需要显式;如果你遇到麻烦,那是你的错。为此,您需要使用
std::ref

int main(void)
{
    double t=1.0;
    printf("%f\n",t);
    test(t);
    printf("%f\n",t);
    callback(std::bind(test, std::ref(t)));
    printf("%f\n",t);
}
标准库中的其他地方也使用了相同的协议,如
std::thread
构造函数

int f(double x);

auto fun = std::bind(f, 1.0); // stores a copy, not a reference to a temporary
fun();
int main(void)
{
    double t=1.0;
    printf("%f\n",t);
    test(t);
    printf("%f\n",t);
    callback(std::bind(test, std::ref(t)));
    printf("%f\n",t);
}