gpt4 book ai didi

c++ - std::bind 是否实现了 std::ref 和 std::cref 来消除函数调用的歧义?

转载 作者:行者123 更新时间:2023-12-02 01:13:48 38 4
gpt4 key购买 nike

我知道我不应该重载函数,因为参数仅在其中一个通过拷贝传递而另一个通过引用传递时有所不同:

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;
}

输出:

Passed by value.

Passed by reference.

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或不;如果是,请将其打开。

关于c++ - std::bind 是否实现了 std::ref 和 std::cref 来消除函数调用的歧义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59795078/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com