【问题标题】:c++ is it possible to to point to a function with its variables definedc ++是否可以指向一个定义了变量的函数
【发布时间】:2016-12-14 03:28:12
【问题描述】:

我依稀记得python允许类似的东西

def foo( x ):
    ....

f = foo( 5 )

在 c++ 中是否有可能,所以如果我有一个成员函数

class C {

    void foo( int x ) { ... }

so that I can define a pointer or variable that would effectively point at foo( 5 )

我之所以要这样做是因为我有很多听众需要订阅回调并保留被调用的信息

class C {
     map<int, ptrSender> m_sender;

    void subscribe() {
        for (const auto& p : m_sender) {
            p .second->register( Callback( this, &C::onCall ) )
        }

我的问题是 onCall 不会返回哪个发件人回电,但我需要这些信息。所以,不要做这样的事情

    void subscribe() {
         m_sender[0]->register( Callback( this, onCall_0 ) );
         m_sender[1]->register( Callback( this, onCall_1 ) );
         ....

   void onCall( int sender_id ) { ... }
   void onCall_0() { onCall( 0 ); }
   void onCall_1() { onCall( 1 ); }
   ....

我希望我可以将一些东西传递到寄存器中,它会返回一个带有预设参数的调用。这可能吗?

编辑:我正在尝试使用 lambda 函数,但遇到以下问题

auto setCall= [this]( int v ) { &C::onCall( v ); }

给出编译错误

lvalue required as unary&opeand

这个

auto setCall= [this]( int v ) { C::onCall( v ); }
.... 
p.second->register( Callback( this, &setCall( p.first) ) );   /// <__ error now here

再次抱怨,现在在第二行

lvalue required as unary&operand

还有这个

auto setCall= [this]( int v ) { C::onCall( v ); }
.... 
p.second->register( Callback( this, setCall( p.first) ) );   /// <__ error now here

抱怨无效使用 void 表达式,但我认为我必须传入一个引用才能使注册函数快乐

回调似乎被定义为

#  define CallBack(obj,func) ProfiledBasicCallBack(obj,fastdelegate::FastDelegate0<void>(obj,func),#func)

【问题讨论】:

标签: c++ function-pointers


【解决方案1】:

是的,您可以使用std::bind。用法示例:http://ideone.com/akoWbA

void foo( int x ) { cout << x << endl; }
auto x = std::bind(foo, 5);
x();

但是,对于现代 C++,您应该使用 lambda。像这样:

void foo( int x ) { cout << x << endl; }
auto x = []() { foo(5); };
x();

请注意,此 foo 函数在此示例中位于 C 类之外。如果您希望将其包含在其中,则需要使用 std::bind 传递您希望调用的对象的实例,例如

C c;
auto x = std::bind(&C::foo, &c, 5);
x();

或使用 lambda:

C c;
auto x = [&c]() { c.foo(5); };
x();

【讨论】:

  • @smac89 谢谢,我的错。
  • 如果你有 std::bind 可用,你将有 lambdas。它们出现在同一个标​​准版本中。在 c++11 中有一些 bind 的用例,但它大多已经过时了。从 c++14 开始,没有任何情况下 bind 是比 lambda 更好的工具。使用 lambdas。
【解决方案2】:

您正在寻找的是std::bind()。它接受一个可调用对象,并为您提供另一个具有预定义参数值的可调用对象,可能还有一些可选参数转发给它。

警告:这是一个相当陡峭的学习曲线。您需要了解模板。

【讨论】:

  • 我绝不会推荐 std::bind 而不是 lambda 函数。它更难理解,而使用[&amp;](){},您可以更轻松地控制需要复制的内容以及可以简单参考的内容。
【解决方案3】:

如果您想将参数值绑定到编译时常量参数(例如您的示例中的5),那么可以通过引入一个简单的包装函数来解决该问题,该函数将在传递所需常量的同时调用您的函数值作为对应的参数。

但是当参数是运行时值时,答案是否定的:通常不可能在 C++ 中创建此类 函数指针 绑定的可信实现(除非您使用一些编译器特定的扩展)。

但是,在 C++ 中,您可以使用多种替代工具。你可以创建一个函数对象来模仿你想要的功能。这样的函数对象可以使用std::bind创建,也可以使用lambda表达式创建,甚至可以手动实现。

生成的 函数对象 将是“可调用的”,并且在表面上与函数指针的行为相似,但它不会是 函数指针,不会t 可转换为 函数指针,并且在需要真正的 函数指针 时不被接受。换句话说,如果你的register 方法被声明为期望一个函数指针作为它的第二个参数,那么你在这里无能为力。 std::bind、lambdas 或该语言中的任何其他内容都不会帮助您实现这种参数绑定。

因此,在此类设计中避开函数指针并根据通用可调用对象实现此类功能通常是一个好主意。最简单的使用方法可能是用std::function 对象代替原始函数指针。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多