【问题标题】:How to declare a templated function so that can be passed in a class constructor/function如何声明模板化函数以便可以在类构造函数/函数中传递
【发布时间】:2018-04-04 09:46:55
【问题描述】:

我想将用户定义的函数传递给需要用户定义的匹配函数的类。在过去的 C 语言时代,我会使用带有 void* 参数的函数指针。但一定有更好的办法……

这大概是我想做的事情。我的一个限制是我所在的平台没有标准库。但是基本的核心语言C++11是可用的。

我需要做什么:

#include <iostream>

using namespace std;

// TODO - replace this C construct with C++ equivalent
//typedef bool(*match_key)(const void* key1, const void* key2);

// somehow declare this as a typedef?  need a way to declare a signature in C++
typedef template<class T>
bool (*match_key)(const T& key1, const T& key2);


// *** User defined matching function
bool mymatcher(const int i, const int j) {
    return i == j;
}

template<class K>
class hashmap {
public:
    hashmap<K>(const K& key, match_key matchfunc) : key_(key), cmp(matchfunc) { }

    bool matched(const K& key) {
        return cmp(key_, key);
    }

private:
    const K key_;
    match_key cmp;
};


int main()
{
    int i = 3;
    int j = 4;

    hashmap<int> hm(i, mymatcher);
    cout << "i matches j? " << (hm.matched(j) ? "yes" : "no") << endl;

    return 0;
}

【问题讨论】:

  • 你错过了template &lt;class K&gt;public:之间的class hashmap {吗?
  • @user463035818 - 只是检查你是否注意了:)

标签: c++ function-pointers function-prototypes


【解决方案1】:
#include <iostream>

using namespace std;

// TODO - replace this C construct with C++ equivalent
//typedef bool(*match_key)(const void* key1, const void* key2);

// somehow declare this as a typedef?  need a way to declare a signature in C++
typedef template<class T>
using match_key = bool (*)(const T& key1, const T& key2);


// *** User defined matching function
bool mymatcher(const int i, const int j) {
    return i == j;
}

template<class K>
class hashmap{
public:
    hashmap(const K& key, match_key<K> matchfunc) : key_(key), cmp(matchfunc) { }

    bool matched(const K& key) {
        return cmp(key_, key);
    }

private:
    const K key_;
    match_key<K> cmp;
};


int main()
{
    int i = 3;
    int j = 4;

    hashmap<int> hm(i, mymatcher);
    cout << "i matches j? " << (hm.matched(j) ? "yes" : "no") << endl;

    return 0;
}

【讨论】:

    【解决方案2】:

    如果match_keyT应该与hashmap的K相同,则可以将hashmap的签名部分设为:

    template <typename T>
    struct hashmap {
        typedef bool (*match_key)(const T& key1, const T& key2);
        ....
    }
    

    ...否则我会将比较器的类型作为第二个模板参数:

    template <typename K, typename C>
    struct hashmap {
         C cmp;
         hashmap(const K& key, C matchfunc) : key_(key), cmp(matchfunc) { }
         ...
    }
    

    这将为用户提供更大的灵活性,但也为长时间的编译器错误打开了大门。

    【讨论】:

      【解决方案3】:

      将函数作为指针传递的方式在 C++ 中非常受限制。它不能在 C++ 中包含任何可调用对象。具体来说就是会阻塞C++中functor的使用。

      这里的函子,指的是任何满足的类型T:

      1. 调用运算符重载;

      或者

      1. 具有用户定义的转换函数,可以将其静态转换为函数指针。

      无论哪种情况,这种类型的任何对象都是可调用的,并且可以像函数名称一样使用。

      这方面的一个例子是std::less,它在使用需要比较两个对象的算法时经常使用。

      为了能够传递任何可调用对象,您必须模板化函数的类型:

      template <class K, class Cmp = std::less<>>
      class hashmap {
      public:
          hashmap<K>(const K& key, Cmp _cmp = {}): key_(key), cmp(_cmp) { }
      
          bool matched(const K& key) {
              return cmp(key_, key);
          }
      
      private:
          const K key_;
          Cmp cmp;
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-10
        • 2011-05-24
        • 2022-11-20
        • 2018-12-08
        • 1970-01-01
        • 2018-07-12
        • 1970-01-01
        相关资源
        最近更新 更多