【问题标题】:How to pass a function callback to a class member?如何将函数回调传递给类成员?
【发布时间】:2011-11-14 18:25:07
【问题描述】:

我正在模板化一个队列类,因此我可以将它与任何东西一起使用,从整数到我需要定义的任何结构。

我需要将一个比较函数传递给类构造函数,一个用于 int 的预定义比较函数等,然后让客户端提供他们可能需要的任何比较函数。但是我该怎么做呢?

template<typename Type>
int cmpFn(Type one, Type two)
{
    if (one < two) return -1;
    if (one > two) return 1;
    return 0;
}

template <typename Type>
class Queue
{
    public:
        Queue()
        {
            Type *list = new Type[size];
            // What do I do now?
            // How to define this constructor?
            // It must pass a comparison function
            // to a private sort method in this class.
        }
    private:
        void sortFunc(Type list, int(fn)(Type one, Type  two)=cmpFn);
};

上面的代码可能有一些错误,因为我只是从头顶写下来以使我的问题更清楚。但我感兴趣的只是在定义类时如何将比较函数传递给排序方法。

这是一项个人练习,我没有参加任何课程,也没有接触任何导师。我已经在谷歌上搜索了一段时间,但我无法找到正确的答案......我想我没有向 Google 先生提出正确的问题。

附: 客户端可能希望为任何类型的数据提供比较功能,例如:

struct individual
{
    string name;
    int age;
    double height;
};

我猜构造函数应该是这样的:

Queue(int (*fn)(Type, Type) = cmpFn);

但是我该如何定义/实现呢?使用这个回调函数的不是Queue对象本身,而是它的方法:sort();

【问题讨论】:

  • 这不是一个答案,但本着 C++ 的精神,我会以不同的方式设计它;即,期望T 带有operator&lt;std::less&lt;T&gt; 的特化,并将其用于排序。甚至可能公开迭代器,尽管这对于类似队列的结构可能没有帮助。

标签: c++ templates function callback pass-by-reference


【解决方案1】:

这是我认为您想要的一个有效的、可编译的示例:

#include <cstddef>
#include <string>
#include <iostream>

template<typename Type>
int cmpFn(Type one, Type two)
{
    if (one < two) return -1;
    if (one > two) return 1;
    return 0;
}

template <typename Type>
class Queue
{
    public:
        // This is the typedef for your callback type
        typedef int (*callback)(Type one, Type two);

        Queue(Type *list, size_t size, callback func = cmpFn)
        {
            sortFunc(list, size, func); // works too
        }

    private:
        void sortFunc(Type *list, size_t size, callback func) {
            for (size_t i=0; i<size; i++) {
                for (size_t j=0; j<size; j++) {
                    if (i == j) continue;

                    int val = (*func)(list[i], list[j]);
                    switch (val) {
                        case 1:
                            std::cout << list[i] << " is greater than " << list[j] << "\n";
                            break;
                        case -1:
                            std::cout << list[j] << " is greater than " << list[i] << "\n";
                            break;
                        case 0:
                            std::cout << list[i] << " and " << list[j] << " are equal\n";
                            break;
                    }
                }
            }
        }

};

int stringCmp(std::string one, std::string two) {
    if (one.size() < two.size()) return -1;
    if (one.size() > two.size()) return 1;
    return 0;
}

int main() {
    // compare ints, use generic comparison function (cmpFn)
    int myInts[2] = {1, 2};
    Queue<int> qi(myInts, 2);

    // compare strings, use our own comparison function (stringCmp)
    std::string myStrings[2] = {"foo", "bar"};
    Queue<std::string> qs(myStrings, 2, stringCmp);

    return 0;
}

编译和执行上面的程序应该会给你这个输出:

2 is greater than 1
2 is greater than 1
foo and bar are equal
bar and foo are equal

基本上是做什么的:

  • Queue 构造函数接受 list 数组、其大小和回调函数。
  • 如果未提供回调函数,则使用通用函数 (cmpFn)。
  • 然后它调用 sortFunc 循环遍历 list 数组中的所有元素并使用回调函数比较它们。

在上面的代码中,您有一个带有intstd::string 的示例。

【讨论】:

  • 谢谢!这几乎就是我需要的。现在我只需要弄清楚如何将回调函数引用存储在类对象中。相反,我不希望构造函数自动调用 sortFunc,而是客户端将在需要时以 myqueue.sortFunc(); 的方式调用它。或 myqueue->sortFunc();客户端在构造对象时确实说明了用于排序的比较函数:Queue myqueue(cmpFuncStrings);
  • @user971191:为此,您必须将sortFunc 公开(它是私有的,所以我认为您不会这样做)。如果要存储回调,callback 被定义为一个类型,所以只需声明该类型的成员并在构造函数中定义即可。
  • 我一直都在眼前……谢谢您指出! :)
【解决方案2】:

可能是这样的:

void sortFunc(Type list, int(*fn)(Type one, Type  two) = cmpFn<Type>);

最好通过常量引用而不是复制来传递参数。谁知道它们是否可以复制?

【讨论】:

  • 感谢回复,请问如何让这个类存储客户端提供的比较功能呢?客户端将提供如何比较列表中包含的元素。我自己只定义了标准比较函数。我真的迷路了。
  • 啊,我明白了。您可以将比较函数作为类的模板参数,然后添加相应的构造函数参数。看看set 是如何实现的(或者至少看看它的公共接口)。
  • @user971191:如果你不希望它成为模板参数的一部分,你将不得不做一些类型擦除。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-02
  • 1970-01-01
  • 2020-02-25
  • 2017-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多