将成员函数指针作为参数发送到另一个成员函数中

时间:2017-01-31 16:26:21

标签: c++

我想发送一个成员函数作为参数,但它不会编译。为什么代码不起作用?这就是我写的。如果我通过lambda而不是它可以工作。

void global_func(std::function<void(void)>f)
{
    f();
}

class goo
{
public:
    goo() { }

    void func1()
    {
        std::function<void(void)> fp = &goo::func2;  // get a pointer to the function func2 . Error here or next line

        global_func( fp);
    }

    void func2(void)
    {

    }

};


void main()
{
    goo g1;
    g1.func1();

}

这里的编译器输出(我的程序名是tryvector.cpp)

1>------ Build started: Project: TryVector, Configuration: Debug Win32 ------
1>  TryVector.cpp
1>e:\program files\microsoft visual studio 12.0\vc\include\functional(506): error C2664: 'void std::_Func_class<_Ret,>::_Set(std::_Func_base<_Ret,> *)' : cannot convert argument 1 from '_Myimpl *' to 'std::_Func_base<_Ret,> *'
1>          with
1>          [
1>              _Ret=void
1>          ]
1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>          e:\program files\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Do_alloc<_Myimpl,_Fret(__thiscall goo::* const &)(void),_Alloc>(_Fty,_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>  ,            _Alloc=std::allocator<std::_Func_class<void,>>
1>  ,            _Fty=void (__thiscall goo::* const &)(void)
1>          ]
1>          e:\program files\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Do_alloc<_Myimpl,_Fret(__thiscall goo::* const &)(void),_Alloc>(_Fty,_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>  ,            _Alloc=std::allocator<std::_Func_class<void,>>
1>  ,            _Fty=void (__thiscall goo::* const &)(void)
1>          ]
1>          e:\program files\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset_alloc<_Fret,goo,,std::allocator<std::_Func_class<_Ret,>>>(_Fret (__thiscall goo::* const )(void),_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>  ,            _Alloc=std::allocator<std::_Func_class<void,>>
1>          ]
1>          e:\program files\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset_alloc<_Fret,goo,,std::allocator<std::_Func_class<_Ret,>>>(_Fret (__thiscall goo::* const )(void),_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>  ,            _Alloc=std::allocator<std::_Func_class<void,>>
1>          ]
1>          e:\program files\microsoft visual studio 12.0\vc\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset<void,goo,>(_Fret (__thiscall goo::* const )(void))' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>          ]
1>          e:\program files\microsoft visual studio 12.0\vc\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,>::_Reset<void,goo,>(_Fret (__thiscall goo::* const )(void))' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>          ]
1>          d:\vc++ my files\tryvector\tryvector\tryvector.cpp(42) : see reference to function template instantiation 'std::function<void (void)>::function<void(__thiscall goo::* )(void)>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Fx=void (__thiscall goo::* )(void)
1>          ]
1>          d:\vc++ my files\tryvector\tryvector\tryvector.cpp(42) : see reference to function template instantiation 'std::function<void (void)>::function<void(__thiscall goo::* )(void)>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Fx=void (__thiscall goo::* )(void)
1>          ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

6 个答案:

答案 0 :(得分:6)

std::function<void(void)>是可以调用的东西,没有任何参数,也没有任何进一步的上下文。

但是,

goo:func2是一个非静态成员函数。它不能被称为; 需要goo个实例。它好像有一个不可见的参数:void func2(goo* const this)。这是有道理的,因为func2可能需要其他一些非静态goo成员来完成它的工作。

您有几种选择:

  • 使用lambda捕获this,即:auto const fp = [this] { func2(); };。请记住,这等于auto const fp = [this] { this->func2(); };
  • 如果func2不需要goo的任何非静态成员,请创建函数static
  • 使用std::bind

答案 1 :(得分:2)

成员函数指针无法包装到std::function<void(void)>中,因为成员函数具有隐式参数:指针this。但是你定义的函数包装器只需要使用nullary callables。

解决方案1:将函数包装器更改为std::function<void(goo*)>。这将要求您修改global_func以传递参数。

解决方案2:使用std::bind生成一个仿函数,其中隐式指针绑定到某个实例。

答案 2 :(得分:2)

这是因为成员函数没有匹配的签名。它还包含隐式this。您可以通过绑定成员函数和this

来创建示例
#include <functional>

void global_func(std::function<void(void)>f)
{
    f();
}

class goo
{
public:
    goo() { }
    void func1()
    {
        std::function<void(void)> fp = std::bind(&goo::func2, this);
        global_func( fp);
    }

    void func2(void) { }
};

int main()
{
    goo g1;
    g1.func1();
}

Lambda有效,因为它可以捕获this

静态函数也可以工作,因为它没有隐式this参数。

基本上你需要一个代表你调用函数的实例,所以在你的情况下this似乎是合理的。

答案 3 :(得分:2)

成员函数具有隐式this参数作为其第一个参数。

goo::func2(void)

实际上是

goo::func2(goo* const this);

你可以做以下两件事之一:

更改global_func的签名以接受std::function<void(goo*)>

的类型

使用std::bind绑定this参数。

std::function<void(void)> fp = std::bind(&goo::func2, this);
global_func(fp);

答案 4 :(得分:2)

您需要使func2成为静态类成员函数,或者在将其转换为this时将其绑定到std::function

 std::function<void()> fp = std::bind(&goo::func2, this);

更多 - 您的代码中还有一些其他不寻常的结构。虽然它们有效,但它们并不是很好的C ++实践:

  

void func2(void)

这是C Style,在C ++中你只需要写void func2()。也:

void global_func(std::function<void()>f) // <-- not void(void)

最后,int main()不是void main()

答案 5 :(得分:0)

因为非静态成员函数不是函数。在常见的实现中,它包含一个指向它所作用的对象的隐藏指针(<script> var modal = document.getElementById('myModal'); var img = document.getElementById('myImg'); var modalImg = document.getElementById("img"); var captionText = document.getElementById("caption"); img.onclick = function(){ modal.style.display = "block"; modalImg.src = this.src; captionText.innerHTML = this.alt; } var span = document.getElementsByClassName("close")[0]; span.onclick = function() { modal.style.display = "none"; } </script> )。

只有静态方法可以和函数一样使用。