std::bind 是否实现了 std::ref 和 std::cref 来消除函数调用的歧义?
Did std::bind implement std::ref and std::cref to disambiguate the function call?
我知道我不应该重载一个函数,因为只有参数的不同之处在于其中一个通过复制传递,另一个通过引用传递:
void foo(int x)
{
cout << "in foo(int x) x: " << x << endl;
}
void foo(int& x)
{
cout << "in foo(int& x) x: " << x << endl;
}
int main()
{
int a = 1;
foo(5); // ok as long as there is one best match foo(int)
foo(a); // error: two best candidates so the call is ambiguous
//foo(std::move(a));
//foo(std::ref(an)); // why also this doesn't work?
}
因此,使用std::bind
的代码可以是这样的:
std::ostream& printVec(std::ostream& out, const std::vector<int> v)
{
for (auto i : v)
out << i << ", ";
return out;
}
int main()
{
//auto func = std::bind(std::cout, std::placeholders::_1); // error: stream objects cannot be passed by value
auto func = std::bind(std::ref(std::cout), std::placeholders::_1); // ok.
}
那么std::ref
在这里确保通过引用而不是按值传递以避免歧义? *对我来说很重要的事情:std::bind()
是否实现了一些包装器来克服这个问题?
- 为什么我不能在我的示例中使用
std::ref
来帮助编译器进行函数匹配?
既然您知道当重载解析尝试比较它们以选择最佳可行函数时,按值和引用传递是不明确的,让我们回答如何使用std::ref
(或std::cref
(来区分按值传递和按引用传递。
原来是...很简单。只需编写重载,使一个接受int
,另一个接受std::reference_wrapper<int>
:
#include <functional>
#include <iostream>
void foo(int x) {
std::cout << "Passed by value.n";
}
void foo(std::reference_wrapper<int> x) {
std::cout << "Passed by reference.n";
int& ref_x = x;
ref_x = 42;
/* Do whatever you want with ref_x. */
}
int main() {
int x = 0;
foo(x);
foo(std::ref(x));
std::cout << x << "n";
return 0;
}
输出:
按值传递。
通过引用传递。
42
默认情况下,该函数按值传递参数。如果要按引用传递,请显式使用std::ref
。
现在让我们回答你的第二个问题:std::bind
如何处理这种情况。这是我创建的一个简单的演示:
#include <functional>
#include <type_traits>
#include <iostream>
template <typename T>
struct Storage {
T data;
};
template <typename T>
struct unwrap_reference {
using type = T;
};
template <typename T>
struct unwrap_reference<std::reference_wrapper<T>> {
using type = std::add_lvalue_reference_t<T>;
};
template <typename T>
using transform_to_storage_type = Storage<typename unwrap_reference<std::decay_t<T>>::type>;
template <typename T>
auto make_storage(T&& obj) -> transform_to_storage_type<T> {
return transform_to_storage_type<T> { std::forward<T>(obj) };
}
int main() {
int a = 0, b = 0, c = 0;
auto storage_a = make_storage(a);
auto storage_b = make_storage(std::ref(b));
auto storage_c = make_storage(std::cref(c));
storage_a.data = 42;
storage_b.data = 42;
// storage_c.data = 42; // Compile error: Cannot modify const.
// 0 42 0
std::cout << a << " " << b << " " << c << "n";
return 0;
}
它不是std::bind
,但使用的方法相似(它也类似于具有相同语义的std::make_tuple
(。 默认情况下,make_storage
复制参数,除非您显式使用std::ref
。
如您所见,std::ref
不是魔法。您需要做一些额外的事情才能使其工作,在我们的例子中是首先衰减类型(在此过程中删除所有引用(,然后检查最终类型是否为reference_wrapper
;如果是,请打开包装。
相关文章:
- 从类型std::函数传递变量失败,尽管调用方期望的类型完全相同
- 类型擦除的std::function与虚拟函数调用的开销
- 如何调用存储在指向"std::函数"的指针中的 lambda?
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 将参数打包的参数传递到 std::queue 中,以便稍后使用不同的函数调用
- std::bind 是否实现了 std::ref 和 std::cref 来消除函数调用的歧义?
- 通过直接函数调用将 std::p romise 对象传递给函数
- 使用 std::find 时没有匹配的函数调用错误
- 为什么 c++11 std::normal_distribution 在从函数调用时返回相同的模式?
- 可变参数模板函数:调用没有匹配函数,std::endl
- 在调用过程中删除 std::函数
- 复制elision、std::move和链式函数调用
- 调用std::函数成员时内存损坏
- 对std::函数对象的调用不匹配,该对象是指向成员函数的指针
- 如何通过 std::apply 调用具有定义的第一个参数的可变参数模板函数?
- 使用 std::function 调用函数作为带有 lambda 的参数
- std::atexit 从全局对象的构造函数调用时的排序
- 防止调用某些 std 函数
- 通过std::函数调用可变函数模板
- 哪些std函数调用交换函数的用户实现版本