std::ref
为您提供了lvalue-reference
。该引用被包装到一个对象中,然后您可以通过引用或值来传递它。
预期行为是它打印i is 2
,但是它打印i is 1
。 为什么呢?
为什么会有这个期望?因为我正在通过tmp
将std::ref
传递给wrapper
。然后在包装器中按值捕获引用。我以为,因为我使用的是std::ref
,所以该值现在仍然是对tmp
的引用。我正在更改tmp
,并希望f
反映出该更改。
#include <iostream>
#include <functional>
template<typename F>
auto wrapper(int i, F func) {
return [=]() { return func(i); };
}
void f(int i) {
std::cout << "i is " << i << '\n';
}
int main() {
int tmp = 1;
auto func = wrapper(std::ref(tmp), f);
tmp = 2;
func();
}
之所以不起作用,是因为您的wrapper
函数将int
作为参数。
std::ref
返回std::reference_wrapper
。当您将其传递给需要int
的函数时您将获得隐式转换,并且不再使用参考。
如果您将功能签名更改为使用std::reference_wrapper
,它将给出预期的结果。
#include <iostream>
#include <functional>
template<typename F>
auto wrapper(std::reference_wrapper<int> i, F func) {
return [=]() { return func(i); };
}
void f(int i) {
std::cout << "i is " << i << '\n';
}
int main() {
int tmp = 1;
auto func = wrapper(std::ref(tmp), f);
tmp = 2;
func();
}
您需要更改功能签名以接受引用:
auto wrapper(int& i, F func) {...}
void f(int& i) {...}
并且还通过参考return [&]() { return func(i); };
进行lambda捕获。然后,您不需要std::ref
。
完整代码如下:
#include <iostream>
#include <functional>
template<typename F>
auto wrapper(int& i, F func) {
return [&]() { return func(i); };
}
void f(int& i) {
std::cout << "i is " << i << '\n';
}
int main() {
int tmp = 1;
auto func = wrapper(tmp, f);
tmp = 2;
func();
}
现在上面的代码将打印:
i is 2
如果您仍想使用std::ref
,则您的模板函数应具有以下签名:
template<typename F>
auto wrapper(std::reference_wrapper<int> i, F func) {...}