std::bind 如何按值获取可变参数,即使它具有通用引用?

How does std::bind take variadic arguments by value, even with its universal reference?

std::bind()is as follows的函数签名:

template< class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );

所以args是一个可变参数模板通用引用,如果我没理解错的话。通用引用的传统模板类型推导规则如下:

  1. 如果传递给 T 的参数是左值,则 T 被推导为左值引用
  2. 如果传递给 T 的参数是右值,则 T 被推导为左值

... 我认为这些规则将单独应用于 args 中的每个 arg,这意味着作为参数传递给 std::bind() 的所有左值都将通过引用传递。然而,这与下面的程序相矛盾:

#include <iostream>
#include <functional>

void function(int& n) {
  n++;
}

int main() {
    int n = 0;
    auto functor = std::bind(function, n);
    functor();
    std::cout << n << std::endl; // 0, not 1.
    return 0;
}

为了让 n 通过引用传递,您必须通过 std::ref(n) 明确地这样做,考虑到我对通用引用和完美转发的了解(很少),这真的让我感到困惑。 std::bind() 在使用通用引用时如何按值取值,否则通用引用会使用左值作为引用?

和签名几乎没有关系,是一种设计选择。 std::bind 当然必须以某种方式存储所有绑定参数,并将它们存储为值。 “通用性”仅用于正确构造它们 - 通过移动或复制。

std::ref 也是按值存储,但由于其性质,包装对象是按引用“存储”的。

std::thread 具有完全相同的行为。可以争辩说(移动)默认构造一个副本更安全,因为两个返回的对象往往比最有可能被捕获的本地对象活得更久。