【问题标题】:A little hazy about std::ref() and std::bind() with variadic templates关于带有可变参数模板的 std::ref() 和 std::bind() 有点模糊
【发布时间】:2016-06-11 08:00:51
【问题描述】:

我已经阅读了很多关于可变参数模板和 std::bind 的帖子,但我想我仍然不明白它们是如何协同工作的。我认为我的概念在使用可变参数模板、std::bind 的用途以及它们如何联系在一起时有点模糊。

在下面的代码中,我的 lambda 对 TestClass 类型的对象使用点运算符,但即使我传入 std::ref 类型的对象,它们仍然可以工作。这到底是怎么回事?隐式转换是如何发生的?

#include <iostream>
using std::cout;
using std::endl;
#include <functional>
#include <utility>
using std::forward;

class TestClass {
public:
    TestClass(const TestClass& other) {
        this->integer = other.integer;
        cout << "Copy constructed" << endl;
    }
    TestClass() : integer(0) {
        cout << "Default constructed" << endl;
    }
    TestClass(TestClass&& other) {
        cout << "Move constructed" << endl;
        this->integer = other.integer;
    }

    int integer;
};

template <typename FunctionType, typename ...Args>
void my_function(FunctionType function, Args&&... args) {
    cout << "in function" << endl;
    auto bound_function = std::bind(function, args...);
    bound_function();
}

int main() {

    auto my_lambda = [](const auto& one, const auto& two) {
        cout << one.integer << two.integer << endl;
    };

    TestClass test1;
    TestClass test2;
    my_function(my_lambda, std::ref(test1), std::ref(test2));

    return 0;
}

更具体地说,我通过两个TestClass 对象test1test2 传递了reference_wrapper 的两个实例,但是当我将它们传递给lambda 时,. 运算符会神奇地工作。我希望您在reference_wrapper 中使用::get() 函数来完成这项工作,但对.integer 数据成员的调用有效..

【问题讨论】:

  • “隐式转换是如何发生的?” - 什么类型之间的隐式转换?
  • 我会更新我的问题以更清楚。对此感到抱歉
  • @soon 那里!这会让我的问题更清楚吗?
  • 是的,我现在明白你的问题了。

标签: c++ templates c++11 c++14 variadic-templates


【解决方案1】:

引用解包由std::bind()的结果执行:

如果参数的类型为 std::reference_wrapper&lt;T&gt;(例如,std::refstd::cref 在对 bind 的初始调用中使用),则存储在绑定参数中的引用 T&amp; 将传递给可调用对象。

相应的标准语可以在 N4140 草案中找到,[func.bind.bind]/10。

【讨论】:

  • 哇!这太神奇了。您还可以建议我可以从哪里了解更多关于这些 std::bind 和可变参数模板的信息吗?因为目前它们对我来说就像魔法一样,当事情看起来像魔法时,我真的无法编程......
  • @Curious:值得一提的是,您可能应该分别研究绑定和可变参数模板。它们没有任何不寻常的相互作用,无论有无可变参数,绑定的行为完全相同,而可变参数的行为无论有无绑定都完全相同。因此,单独研究它们就不会那么让人头疼了。
【解决方案2】:

需要注意的是std::bind;

bind 的参数被复制或移动,并且永远不会通过引用传递,除非包裹在 std::refstd::cref 中。

上面的“通过引用传递”是因为std::ref 提供了std::reference_wrapper 的结果,这是一个“包装”所提供的引用的值类型。

std::reference_wrapper 是一个类模板,它将引用包装在一个可复制、可分配的对象中。它经常被用作将引用存储在标准容器(如std::vector)中的机制,这些容器通常不能保存引用。

举个例子,说明bind 解包引用的作用(没有bind);

#include <iostream>
#include <utility>
#include <functional>

int main()
{
    using namespace std;
    int a = 1;
    auto b = std::ref(a);
    int& c = b;
    cout << a << " " << b << " " << c << " " << endl; // prints 1 1 1
    c = 2;
    cout << a << " " << b << " " << c << " " << endl; // prints 2 2 2
}

Demo code.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-05
    • 2019-04-30
    • 1970-01-01
    • 2018-11-26
    • 1970-01-01
    • 2019-01-18
    • 2014-01-22
    • 2016-04-26
    相关资源
    最近更新 更多