在将函数分配给std :: function类型时,调用哪个函数原型(以及如何)?

时间:2014-06-09 21:06:52

标签: c++ c++11 std-function

我有代码

void prints_one()
{ cout << "one" << endl; }

int main(int argc, char *argv[])
{
    std::function<void()> foo;
    foo = prints_one;
    foo();
    return 0;
}

按预期工作;它打印&#34;一个&#34;。我不知道的是在作业中调用哪个赋值运算符原型以及如何调用。看看cpp引用,看起来它可能就是这个函数

template <class Fn> function& operator= (Fn&& fn);

但如果那是被调用的原型,我就不会理解函数如何绑定到右值引用。谢谢!

更新:谢谢大家,我将阅读全民参考资料。关于40的两个答案;此代码打印出它是一个右值引用:

template<class Fn>
class Foo {
public:
    Foo() {}
    Foo& operator=(Fn&& x)
    {
      std::cout << std::boolalpha << std::is_rvalue_reference<decltype(x)>::value << std::endl;
    }
};

void prints_one()
{
  cout << "one" << endl;
}

int main(int argc, char *argv[])
{
  Foo<void()> bar;
  bar = prints_one;
}

这会打印true

2 个答案:

答案 0 :(得分:8)

C ++标准意味着令人困惑!否则,像我一样的人只是因为他们在C ++标准得到发展的同时正在观看而不能玩智能。为此,我们决定应用于类型的&&符号表示两个完全不同的符号,但也有混淆相关的内容:

  1. 在未推断的上下文中应用时,即使用已知类型T,符号T&&表示正在声明右值引用。
  2. 在推断的上下文中应用时,例如,在auto&& x = ...或函数模板template <typename T> void f(T&& x)中,符号表示:确定类型和&#34;参考度&#34;这个论点。推导出的类型T具有不同的类型,具体取决于作为参数传递的内容:
    1. 如果传递了const类型的非X左值,则T类型将推断为X&T&&变为{{ 1}}作为参考,右值参考折叠成参考。
    2. 如果传递X&类型的const左值,则X类型将推断为TX const&变为T&& },由于相同的参考折叠。
    3. 如果正在传递右值,则X const&类型将被推断为T,而X将变为T&&,因为没有任何内容可以崩溃。
  3. 推动论证推论规则的动机是完美的转发:论证应该转发到下一层,理想情况下看起来就像在第一个地方推断出的论证一样。

    考虑到这一点,被调用的X&&的赋值运算符确实是

    std::function<...>

    其中函数的参数相应地推断出来。在你的具体例子中,实际传递的函数指针通过衰减函数类型而动态创建的右值:函数不是真正的对象,不能在C ++中传递。正在形成除了调用指向函数的指针之外的访问它们。因此,参数是template <typename F> std::function<...>::function(F&& f) 类型的右值。

答案 1 :(得分:2)

here引用内容:

  • T&&并非总是rvalue参考。

  • 类型声明中的
  • &&有时可能意味着rvalue引用,但有时它意味着rvalue引用或lvalue引用。

    < / LI>

我将尝试通过一个例子为上述做出贡献。请考虑以下代码:

#include <iostream>
#include <type_traits>

using namespace std;

template<class F>
void foo(F&& f)
{
  std::cout << std::boolalpha << std::is_rvalue_reference<decltype(f)>::value << std::endl;
}

void prints_one()
{
  cout << "one" << endl;
}

int main(int argc, char *argv[])
{
  foo(prints_one);
  foo([](){ cout << "lambda" << endl; });
  return 0;
}
  • 如果您运行它,则输出为:
  
    

false

         

true

  
  • 这意味着虽然fooT&&作为输入参数,但由于prints_onelvalue,因此输入参数{{1 }}将使用f初始化,因此它将成为lvalue引用。

  • 另一方面,在lvalue的第二次调用中,我们传递foo,这实际上是lambda引用。因此,输入参数rvalue初始化为f,因此它成为rvalue引用。

  • 因此,输入参数是推导为rvalue引用还是lvalue引用取决于在rvalue调用时传递的输入参数。< / p>

更新

关于更新的例子:

  • 您正在使用赋值运算符foo定义模板类Foo

  • 在这种情况下,Foo<T>::operator=(T&&)不是通用引用,因为没有类型扣除。

  • 它更像是T&&引用,因此您获得了rvalue

  • 这是因为true已被班级T扣除。因此,对于成员重载运算符Foo<T>的输入参数,不能进行类型推导。