如何创建一个可以为T选择特殊容器的模板class?
How can I create a template class that can choose special container for T?
我如何创建一个模板 class 可以理解类型 T
是否可散列,如果是则使用 std::unodered_set
收集类型 T 的元素?。否则,我希望它使用 std::set
.
这个class有和上面sets
一样简单的方法,比如insert(), find()
等等
template<class T>
class MySet {
public:
MySet() {}
bool find() {
//some code here
我检查类型是否有 operator()
以获取有关其 "hashability" 的信息。为此,我使用了我在这个网站上找到的以下结构:
template<typename T>
class HasHash {
typedef char one;
typedef long two;
template<typename C>
static one test(decltype(&C::operator()));
template<typename C>
static two test(...);
public:
enum {
value = sizeof(test<T>(0)) == sizeof(size_t)
};
};
输入是否可哈希(真或假):
HasHash<HashableType>::value
我没有办法使用boost库。
如果你有 is_hashable<T>
类型特征(例如你的 HasHash
),那么你可以使用 std::conditional
,像这样:
template <typename T>
std::conditional<is_hashable<T>::value, std::unordered_set<T>, std::set<T>>::type
或者如果您使用的是 C++17,它可以简化为:
template <typename T>
inline constexpr bool is_hashable_v = is_hashable<T>::value;
template <typename T>
std::conditional_t<is_hashable_v<T>, std::unordered_set<T>, std::set<T>>;
(假设您还实现了特征的 _v
版本)。
关于确定可哈希性的一些额外讨论,这也很有趣:
Check if type is hashable
在网站上。
这是一个完整的工作示例,假设您使用的是 std::hash
。
#include <iostream>
#include <set>
#include <unordered_set>
#include <type_traits>
#include <functional>
using std::cout;
using std::endl;
template <typename...> using void_t = void;
template <typename, typename = void>
struct is_hashable : std::false_type { };
template <typename T>
struct is_hashable<T, void_t<decltype(std::hash<T>{})>> : std::true_type { };
template <typename T>
using set = typename std::conditional<
is_hashable<T>::value, std::unordered_set<T>, std::set<T>
>::type;
template <typename T> void test() { cout << __PRETTY_FUNCTION__ << endl; }
struct dummy_type { };
int main(int argc, char* argv[]) {
cout << std::boolalpha;
cout << is_hashable<int>::value << endl;
cout << is_hashable<dummy_type>::value << endl;
test<set<int>>();
test<set<dummy_type>>();
}
输出应该类似于
true
false
void test() [with T = std::unordered_set<int, std::hash<int>, std::equal_to<int>, std::allocator<int> >]
void test() [with T = std::set<dummy_type, std::less<dummy_type>, std::allocator<dummy_type> >]
编辑:
is_hashable
特化也可以不使用 void_t
,像这样:
template <typename T>
struct is_hashable<T, decltype(std::hash<T>{},void())> : std::true_type { };
我如何创建一个模板 class 可以理解类型 T
是否可散列,如果是则使用 std::unodered_set
收集类型 T 的元素?。否则,我希望它使用 std::set
.
这个class有和上面sets
一样简单的方法,比如insert(), find()
等等
template<class T>
class MySet {
public:
MySet() {}
bool find() {
//some code here
我检查类型是否有 operator()
以获取有关其 "hashability" 的信息。为此,我使用了我在这个网站上找到的以下结构:
template<typename T>
class HasHash {
typedef char one;
typedef long two;
template<typename C>
static one test(decltype(&C::operator()));
template<typename C>
static two test(...);
public:
enum {
value = sizeof(test<T>(0)) == sizeof(size_t)
};
};
输入是否可哈希(真或假):
HasHash<HashableType>::value
我没有办法使用boost库。
如果你有 is_hashable<T>
类型特征(例如你的 HasHash
),那么你可以使用 std::conditional
,像这样:
template <typename T>
std::conditional<is_hashable<T>::value, std::unordered_set<T>, std::set<T>>::type
或者如果您使用的是 C++17,它可以简化为:
template <typename T>
inline constexpr bool is_hashable_v = is_hashable<T>::value;
template <typename T>
std::conditional_t<is_hashable_v<T>, std::unordered_set<T>, std::set<T>>;
(假设您还实现了特征的 _v
版本)。
关于确定可哈希性的一些额外讨论,这也很有趣:
Check if type is hashable
在网站上。
这是一个完整的工作示例,假设您使用的是 std::hash
。
#include <iostream>
#include <set>
#include <unordered_set>
#include <type_traits>
#include <functional>
using std::cout;
using std::endl;
template <typename...> using void_t = void;
template <typename, typename = void>
struct is_hashable : std::false_type { };
template <typename T>
struct is_hashable<T, void_t<decltype(std::hash<T>{})>> : std::true_type { };
template <typename T>
using set = typename std::conditional<
is_hashable<T>::value, std::unordered_set<T>, std::set<T>
>::type;
template <typename T> void test() { cout << __PRETTY_FUNCTION__ << endl; }
struct dummy_type { };
int main(int argc, char* argv[]) {
cout << std::boolalpha;
cout << is_hashable<int>::value << endl;
cout << is_hashable<dummy_type>::value << endl;
test<set<int>>();
test<set<dummy_type>>();
}
输出应该类似于
true
false
void test() [with T = std::unordered_set<int, std::hash<int>, std::equal_to<int>, std::allocator<int> >]
void test() [with T = std::set<dummy_type, std::less<dummy_type>, std::allocator<dummy_type> >]
编辑:
is_hashable
特化也可以不使用 void_t
,像这样:
template <typename T>
struct is_hashable<T, decltype(std::hash<T>{},void())> : std::true_type { };