如何声明模板化函数以便可以传入 class constructor/function
How to declare a templated function so that can be passed in a class constructor/function
我想将用户定义的函数传递给需要用户定义的匹配函数的 class。在过去的 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;
}
#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;
}
如果match_key
的T
和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) { }
...
}
这会给用户更大的灵活性,但也为长时间的编译器错误打开了大门。
将函数作为指针传递的方式在 C++ 中非常受限。它无法在 C++ 中包含任何可调用对象。具体来说,就是会屏蔽C++中functor的使用。
这里的函子,指的是任何满足以下条件的类型T:
- 调用运算符重载;
或
- 具有 user-defined 转换函数,可以将其静态转换为函数指针。
无论哪种情况,任何这种类型的对象都是可调用的,并且可以像函数名一样使用。
这方面的一个例子是 std::less,它在使用需要比较 2 个对象的算法时经常使用。
为了能够传递任何可调用对象,您必须模板化函数的类型:
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;
};
我想将用户定义的函数传递给需要用户定义的匹配函数的 class。在过去的 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;
}
#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;
}
如果match_key
的T
和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) { }
...
}
这会给用户更大的灵活性,但也为长时间的编译器错误打开了大门。
将函数作为指针传递的方式在 C++ 中非常受限。它无法在 C++ 中包含任何可调用对象。具体来说,就是会屏蔽C++中functor的使用。
这里的函子,指的是任何满足以下条件的类型T:
- 调用运算符重载;
或
- 具有 user-defined 转换函数,可以将其静态转换为函数指针。
无论哪种情况,任何这种类型的对象都是可调用的,并且可以像函数名一样使用。
这方面的一个例子是 std::less,它在使用需要比较 2 个对象的算法时经常使用。
为了能够传递任何可调用对象,您必须模板化函数的类型:
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;
};