C++成员函数指针和STL算法

3

我有一个抽象的函数类,重载了operator(),并且有派生对象实现它。

我有一个函数(属于另一个类),尝试使用这些函数类的数组,并尝试将成员函数指针传递给std算法for_each()。以下是我正在进行的概述:

编辑:我已经重新清理过,并放置了旧的小示例以便更加清晰。

class A{
  operator()(x param)=0;
  operator()(y param)=0;
}

class B: public A{
  operator()(x param); //implemented
  operator()(y param);
}
...// and other derived classes from A

void ClassXYZ::function(A** aArr, size_t aSize)
{
  ...//some code here

  for(size_t i = 0; i< aSize; i++){

    A* x = aArr[i];
    for(v.begin(), v.end(), ...//need to pass pointer/functor to right operator() of x here

..//other code
}

我尝试了几种方法,但无法弄清如何使其正常工作。我需要使用抽象类型,因为派生类型可能不同,但它们都必须实现相同的operator()(param x)函数。
我只需要for_each()函数能够调用成员函数operator()(param x)。我有一个不同的函数,它具有具体实现并简单地传递这些实例,因此它可以正常工作。我试图在这里实现类似的效果,但是没有知道我得到了哪些具体类。
我做错了什么?

1
为什么不使用vector而不是指向指针的指针? - GManNickG
它只需要一个参数,参数类型可以是不同的x和y。好的我会尝试发布整个片段。我认为我们已经接近成功了。 - iQ.
好的,我放了清理过的代码片段的版本上去。 - iQ.
1
你误解了我的static_cast<>建议(pFunc不是一个类型),而且bind1st()需要一个对象的指针,而不是一个对象。尝试使用for_each(it->second.begin(), it->second.end(), std::bind1st(std::mem_fun(pFunc), pf)); - j_random_hacker
如果其他方法都失败了,我可以修改我的基类,使得所有派生类必须为每个重载运算符提供一个指针或函数对象的成员函数。 - iQ.
显示剩余17条评论
4个回答

4
您想要类似这样的东西...
std::for_each(
  it->second.begin(),
  it->second.end(),
  std::bind1st(std::mem_fun(&A::operator()),x)
);

1
不错。此外,常规的C++03标准中的bind1st()可以替代您在此处使用的更通用的std::tr1::bind()(可能尚未被所有编译器支持)。 - j_random_hacker
1
mem_fun() 函数可以将一元成员函数(使用 obj->fun(arg) 形式调用)转换为二元普通函数(使用 fun(obj,arg) 形式调用)。 - alex tingle
那对我来说无法编译 :( 我得到的错误信息为:error: no matching function for call to ‘mem_fun(<unresolved overloaded function type>)’| - iQ.
1
@iQ:如果重载是一个问题,可以使用static_cast<>来指定你想要的operator(),例如:mem_fun(static_cast<void (A::*)(param)>(&A::operator()) - j_random_hacker
@iQ:Alex和我的方法基本上是等效的--如果他的方法不起作用,那么我的也不会,反之亦然。你的错误一定来自其他地方。请发布你所拥有的完整代码片段,因为你目前的代码存在太多问题(例如,不匹配的括号!)。 - j_random_hacker
显示剩余5条评论

3
如果我理解您想要做的事情,那么您的代码片段中有相当多的错误:
  • sizeof aArr 是错误的,您需要显式传递大小 (由ChrisW注意到)
  • operator()() 的原始声明缺少 virtual 限定符
  • 不确定您的 for 循环何时结束,因为没有匹配的 } (我怀疑它根本不应该在那里)
以下是一些代码,将循环遍历一个 A (或派生自A)对象的数组,并在每个对象上调用operator(),将传入参数作为param参数传递:
#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;

typedef double param;      // Just for concreteness

class A {
public:
    virtual void operator()(param x) = 0;
};

class B : public A {
public:
    void operator()(param x) { cerr << "This is a B!  x==" << x << ".\n"; }
};

void function(A** aArr, size_t n, param theParam) {
    void (A::*sFunc)(param x) = &A::operator();
    for_each(aArr, aArr + n, bind2nd(mem_fun(sFunc), theParam));
}

int main(int argc, char** argv) {
    A* arr[] = { new B(), new B(), new B() };

    function(arr, 3, 42.69);

    delete arr[0];
    delete arr[1];
    delete arr[2];
    return 0;
}

mem_fun()函数用于将一个带有一个参数的成员函数指针转换为一个带有两个参数的函数对象;bind2nd()然后从中产生一个带有一个参数的函数对象,该函数对象将提供给function()作为第二个参数的参数固定下来。(for_each()需要一个带有一个参数的函数指针或函数对象。)

编辑:根据Alex Tingle的回答,我推断您可能希望function()在单个A派生对象上执行多个操作。在这种情况下,您需要类似于以下内容:

void function(A** aArr, size_t n, vector<param> const& params) {
    for (size_t i = 0; i < n; ++i) {
        void (A::*sFunc)(param x) = &A::operator();
        for_each(params.begin(), params.end(), bind1st(mem_fun(sFunc), aArr[i]));
    }
}

好的,我会尝试一下,因为这是完全标准的C++。我确实使用了虚拟函数,只是忘记在示例中将其排除,我也会修复数组的大小。如果可以的话我会回来发布结果的。 - iQ.
如果你重新阅读,你可能会发现我已经预料到了... :) 如果不是这样,请告诉我需要改变什么。 - j_random_hacker
是的,我无法让任何解决方案起作用,我觉得可能是我做错了什么。作为一个一般性问题,如果你只有一个实例的指针,你如何获得一个成员函数的指针? - iQ.
您是否意识到“成员函数指针”是一种与“函数指针”不同的类型分类?它们之间是不能相互转换的。但是,通过使用bind1st(mem_fun(pMemFunc), pObj),您可以从指向对象和指向成员函数的组合中获取一个可以像函数一样被调用的对象。 - j_random_hacker
是的,这就是我一直在尝试做的事情,但我总是会得到错误:error: no matching function for call to ‘mem_fun(<unresolved overloaded function type>)’——所以我认为我一定做错了什么,我得到了一个对象的指针,我已经尝试过传递解引用指针和指针本身。没有成功。 - iQ.
显示剩余2条评论

1

表达式“bar.*fn”不能评估为常规或非成员函数指针。因此,您需要调用绑定函数(std::tr1::bind或boost::bind)来获取这样的函数。


0

我无法使用当前的格式使其正常工作,我认为它不喜欢我在使用指向基类成员函数的指针并尝试像那样调用派生类实现。

相反,我修改了代码以在基类中包含纯虚函数,当实现时将为每个派生类返回functor。我想不到其他任何可行的方法。但是这样编译就可以了。

但是我好奇是否有人能够提供不必使用基类中的纯虚“create functor”方法的原始问题的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接