指向成员函数的指针

3
我正在尝试将以下Table中的filterX()filterY()函数泛化成filter()函数。 filterX()filterY()函数仅在它们调用过程中调用的函数不同。 filterX()调用getX(),而filterY()调用getY()
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Row 
{
    public:
        void add(string x, string y, int val);
        string getX()   const { return d_x; } 
        string getY()   const { return d_y; } 
        int    getVal() const { return d_val; } 

    private:
        string d_x;
        string d_y;
        int    d_val;
};

class Table
{
    public:
        void add(string x, string y, int val);
        vector<int> filterX(string s);
        vector<int> filterY(string s);
    private:
        vector<Row> d_table;
};


//--------------------class Row----------------------------
void Row::add(string x, string y, int val)
{
    d_x   = x;
    d_y   = y;
    d_val = val;
}


//-------------------class Table---------------------------

void Table::add(string x, string y, int val)
{
    Row r;
    r.add(x, y, val);
    d_table.push_back(r);
}

vector<int> Table::filterX(string s)
{
    vector<int> result;
    vector<Row>::iterator it;
    for(it = d_table.begin(); it != d_table.end(); ++it) {
        if(it->getX() == s) {
            int val = it->getVal();
            result.push_back(val);
        }
    }
    return result;
}


vector<int> Table::filterY(string s)
{
    vector<int> result;
    vector<Row>::iterator it;
    for(it = d_table.begin(); it != d_table.end(); ++it) {
        if(it->getY() == s) {
            int val = it->getVal();
            result.push_back(val);
        }
    }
    return result;
}

int main()
{
    Table t;
    t.add("x1", "y1", 1);
    t.add("x1", "y2", 2);
    t.add("x2", "y1", 3);
    t.add("x2", "y2", 4);

    vector<int> vx = t.filterX("x1");
    vector<int> vy = t.filterY("y2");

    vector<int>::const_iterator it;

    cout << "Matching X" << endl;
    for(it = vx.begin(); it != vx.end(); ++it)
        cout << *it << "\t";
    cout << endl;

    cout << "Matching Y" << endl;
    for(it = vy.begin(); it != vy.end(); ++it)
        cout << *it << "\t";
    cout << endl;

    return 0;
}

我尝试使用成员函数指针,但是遇到了编译器错误。对于下面的例子,如果可能的话,我希望有以下main()

int main()
{
    Table t;
    t.add("x1", "y1", 1);
    t.add("x1", "y2", 2);
    t.add("x2", "y1", 3);
    t.add("x2", "y2", 4);

    // instead of filterX, need to pass getX
    // to a function named filter       
    vector<int> vx = t.filter("x1", getX);
    vector<int> vy = t.filter("y2", getY);

    return 0;
}

感谢所有的回答。我已经选择了其中一个作为答案,很遗憾我不能将它们全部选为答案。对此我感到抱歉。 - Anand
5个回答

2

成员函数需要一个指向对象实例的指针。也就是说,可以把getX看作string Row::getX(const Table *this)。您需要使用实例占位符来bind成员函数。

例如,使用tr1:

vector<int> vx = t.filter("x1", std::bind(&Row::getX, std::placeholders::_1));

绑定操作会创建一个函数对象,接受一个 Row 对象作为参数,并假设你已经正确定义了过滤函数。请展示 filter 的代码。我认为应该是这样的:
template <class function>
vector<int> Table::filter(const string &s, function f)
{
    vector<int> result;
    for (vector<Row>::const_iterator it = d_table.begin(), tEnd = d_table.end();
        it != tEnd; ++it)
    {
        if (s == f(*it)) result.push_back(it->getVal());
    }
    return result;
}

可以的。我的解决方案在运行时略微更快 :p。你应该提到 #include <functional> - J.N.
通过绑定,Row的更一般成员可以被使用。例如,那些需要额外参数的成员。 - devil

1

以下是使用成员函数指针的方法:

// helper to avoid type nightmare;
typedef string (Row::* GetterP)() const;

class Table 
{ 
public: 
    void add(string x, string y, int val); 

    // Define a templated function that can be called with GetX or GetY
    template <GetterP getter>
    vector<int> filter(string s)
    {
         int i = (d_table[i].*getter)(); // how to use getter in filter
    }

private:
    vector<Row> d_table;  
};

// Usage:
Table t;
t.filter<&Row::GetX>("");

请记住,它将为 GetXGetY 创建 Table::filter 的单独副本。我认为 OP 不想要单独的副本(编译时),而是在运行时进行评估。 - iammilind
@iammilind 嗯,确实会重复生成的代码,但是如果编译器做好了它的工作,调用就会快一些,少了一个加法和(也许)一些内联。总体来说,这可能并不那么重要,毕竟这个函数本身并不是很大。 - J.N.

1
如果你想使用显式的PMF(或者至少看看它们是如何被使用的):
声明PMF类型:
class Row 
{
    public:
    typedef string (Row::*getFilter)() const;
     // etc.
};

class Table
{
    public:
    // Call it like this:

    vector<int> pmf_filterX(string s)
    {
        return filter(s, &Row::getX);
    }
    private:
    // Use it like this:
    vector<int> filter(string s, Row::getFilter f)
    {
        vector<int> result;
        vector<Row>::iterator it;
        for(it = d_table.begin(); it != d_table.end(); ++it)
            {
            const Row& row = *it;

            if ((row.*f)() == s) 
                {
                int val = it->getVal();
                result.push_back(val);
                }
            }
        return result;
    }
};

1

这是你想要的语法:

vector<int> Table::filter(string s, string (Row::*get)() const)
{                                  //^^^^^^^^^^^^^^^^^^^^^^^^^^^ member pointer
  ...
  if(((*it).*get)() == s) {  // call using the (*it). and not it->
  ... 
}

调用方式:

vector<int> vx = t.filter("x1", &Row::getX);
vector<int> vy = t.filter("y2", &Row::getY);

感谢您指出应使用(*it)而非it->,非常有帮助。 - Anand

1

在这里修改您的代码:

public:
    void add(string x, string y, int val);
    vector<int> filter(string s, string (Row::*)() const);
private:
    ...

这里:

vector<int> Table::filter(string s, string (Row::*f)() const)
{   
    vector<int> result;
    vector<Row>::iterator it;
    for(it = d_table.begin(); it != d_table.end(); ++it) {
        if((*it.*f)() == s) {
            int val = it->getVal();
            result.push_back(val); 
        }
    }
    return result;
}

在这里:

int main()
{
    ...
    vector<int> vx = t.filter("x1", &Row::getX);
    vector<int> vy = t.filter("y2", &Row::getY);

    ...

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