如何将已知签名的特定对象存储在C++中的变量中?

发布于 2025-01-25 11:23:35 字数 844 浏览 2 评论 0原文

在某些对象实例上存储对特定签名的非静态成员函数的引用的推荐方法是什么?在调用代码不知道对象类(即没有铸件)的方式中,该功能是正确的签名。

例如,如果有两个不同的类带有相同void(int)签名的函数,那么

class Foo {
public:
  int myInt;
  
  void multMyInt(int multiplier) {
    myInt *= multiplier;
  }
};

class Bar {
public:
  bool isBig;
  
  void setMySize(int size) {
    isBig = size > 100;
  }
};

此代码应该是什么样的?

int main() {
  Foo* myFoo = new Foo();
  Bar* myBar = new Bar();

  int x = 10;

  callIntFunc(x, /* myFoo->multMyInt() */);
  callIntFunc(x, /* myBar->setMySize() */);
}

// Calls any function which matches void(int).
void callIntFunc(int inInt, /* function stored in some way */) {
  // call given function with inInt as the parameter
}

建议仅使用标准库做到这一点的建议方法是什么?

PS表示歉意,如果这是一个重复的问题。我已经搜索了任何想到的术语,找不到它。

What is the recommended way to store a reference to a non-static member function of a specific signature on some object instance? In a way where the calling code needs not to know of the object's class (i.e. no casting), just that the function is the correct signature.

For example, if there are two different classes with functions of the same void(int) signature, like

class Foo {
public:
  int myInt;
  
  void multMyInt(int multiplier) {
    myInt *= multiplier;
  }
};

class Bar {
public:
  bool isBig;
  
  void setMySize(int size) {
    isBig = size > 100;
  }
};

What should this code look like?

int main() {
  Foo* myFoo = new Foo();
  Bar* myBar = new Bar();

  int x = 10;

  callIntFunc(x, /* myFoo->multMyInt() */);
  callIntFunc(x, /* myBar->setMySize() */);
}

// Calls any function which matches void(int).
void callIntFunc(int inInt, /* function stored in some way */) {
  // call given function with inInt as the parameter
}

What is the recommended approach to doing this using standard library only?

p.s. Apologies if this is a repeat question. I have searched in any terms that came to mind, and couldn't find it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

歌入人心 2025-02-01 11:23:35

由于您不仅要存储指向成员函数的指针,还要存储该函数应访问的对象,因此您需要一种将两者都存储在单一对象中的方法。

由于C ++具有LAMBDA函数,因此您可以将它们拿走并像从代码修改的以下示例中一样使用它们。

class Foo {
    public:
        int myInt;

        void multMyInt(int multiplier) {
            std::cout << "Calls multMyInt" << std::endl;
            myInt *= multiplier;
        }
};

class Bar {
    public:
        bool isBig;

        void setMySize(int size) {
            std::cout << "Calls setMySize" << std::endl;
            isBig = size > 100; 
        }
};

// Calls any function which matches void(int).
void callIntFunc(int inInt, auto& func )
{
    func(inInt);
}


int main() {
    Foo* myFoo = new Foo();
    Bar* myBar = new Bar();

    auto multMyInt = [myFoo](int parm){ myFoo->multMyInt(parm);};
    auto setMySize = [myBar](int parm){ myBar->setMySize(parm);};

    int x = 10;



    callIntFunc(x, multMyInt);
    callIntFunc(x, setMySize);
}

在C ++ 11之前,您必须使用std :: bind,但实际上不需要。

您还可以使用std :: function来使用auto,而是将inder -code使用:

// Calls any function which matches void(int).
void callIntFunc(int inInt, std::function<void(int)>& func )
{
    func(inInt);
}


int main() {
    Foo* myFoo = new Foo();
    Bar* myBar = new Bar();

    std::function<void(int)> multMyInt = [myFoo](int parm){ myFoo->multMyInt(parm);};
    std::function<void(int)> setMySize = [myBar](int parm){ myBar->setMySize(parm);};

    int x = 10;



    callIntFunc(x, multMyInt);
    callIntFunc(x, setMySize);
}

使用auto需要的模板版本为每个函数生成的其他程序内存类型A型新实例,但它很快。

std :: function版本需要更少的程序空间,但会导致稍微运行时开销。这取决于您喜欢的需求!

评论的更新:

在使用Lambdas的情况下,在您使用指示器或参考文献的所有其他情况下,没有什么特别的范围。但是您必须注意:

  • 如果您通过引用捕获,则引用的对象必须活着,如果您调用函数 / lambda。
  • 如果您捕获对象的副本,则将获得新的独立副本。因此,只要Lambda还活着,它是有效的,但是您可以参考副本而不是原始对象。

auto的类型是什么:

每个lambda都会产生一种新类型。该类型本身总是被实现隐藏和生成。这就是为什么您必须使用auto

As you have to store not only the pointer to the member function but also the object which the function should access, you need a way to store both in a single kind of object.

As C++ has lambda functions you simply can take them and use them like in the following example modified from your code.

class Foo {
    public:
        int myInt;

        void multMyInt(int multiplier) {
            std::cout << "Calls multMyInt" << std::endl;
            myInt *= multiplier;
        }
};

class Bar {
    public:
        bool isBig;

        void setMySize(int size) {
            std::cout << "Calls setMySize" << std::endl;
            isBig = size > 100; 
        }
};

// Calls any function which matches void(int).
void callIntFunc(int inInt, auto& func )
{
    func(inInt);
}


int main() {
    Foo* myFoo = new Foo();
    Bar* myBar = new Bar();

    auto multMyInt = [myFoo](int parm){ myFoo->multMyInt(parm);};
    auto setMySize = [myBar](int parm){ myBar->setMySize(parm);};

    int x = 10;



    callIntFunc(x, multMyInt);
    callIntFunc(x, setMySize);
}

In times before C++11 you have to use std::bind but that is really not longer needed.

Instead of using auto in connection with lambda, you can also go with std::function which results in:

// Calls any function which matches void(int).
void callIntFunc(int inInt, std::function<void(int)>& func )
{
    func(inInt);
}


int main() {
    Foo* myFoo = new Foo();
    Bar* myBar = new Bar();

    std::function<void(int)> multMyInt = [myFoo](int parm){ myFoo->multMyInt(parm);};
    std::function<void(int)> setMySize = [myBar](int parm){ myBar->setMySize(parm);};

    int x = 10;



    callIntFunc(x, multMyInt);
    callIntFunc(x, setMySize);
}

The templated version which uses auto needs some more program memory as it generates for each function type a new instance, but it is fast.

The std::function version needs less program space but results in a bit runtime overhead. It depends on your needs what you prefer!

Update from comments:

There is nothing special regarding the scope in case of using lambdas as in every other situation where you use pointers or references. But you have to take care:

  • if you capture by reference, the referenced object must be alive if you call the function / lambda.
  • if you capture a copy of the object, you get a new independent copy. As this, it is valid as long the lambda is alive, but you reference to a copy and not the original object.

What is the type of auto:

Every lambda results in a new type. The type itself is always hidden and generated by the implementation. That is why you have to use auto.

苏辞 2025-02-01 11:23:35

使用 std :: bind_front 。它与另一个答案中建议的自定义lambda相同,但语法较少。

auto func = std::bind_front(&Foo::multMyInt, myFoo);
func(42);

请注意,我们将类Pointer 作为第二个参数。如果我们取而代之的是值,则类实例将被复制到函子中。

这里auto扩展到某些未指定的类型,但是您可以用std :: function&lt; void(int)&gt;替换它。

Use std::bind_front. It does the same thing as a custom lambda suggested in the other answer, but the syntax is less verbose.

auto func = std::bind_front(&Foo::multMyInt, myFoo);
func(42);

Note that we pass the class pointer as the second argument. If we instead pass by value, the class instance will be copied into the functor.

Here auto expands to some unspecified type, but you can replace it with std::function<void(int)>.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文