【问题标题】:How can I create a template class that can choose special container for T?如何创建可以为 T 选择特殊容器的模板类?
【发布时间】:2018-03-16 23:49:46
【问题描述】:

如何创建一个模板类,它可以理解T 类型是否是可散列的,如果是,则使用std::unodered_set 来收集T 类型的元素?否则,我希望它使用std::set

这个类和上面sets一样的简单方法如insert(), find()等等。

template<class T>
class MySet {
public:
    MySet() {}
    bool find() {
    //some code here

我检查类型是否有operator() 以获取有关其“哈希性”的信息。为此,我使用了我在这个网站上找到的以下结构:

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)
    };
};

通过键入以下内容,get 是否可散列(真或假):

HasHash<HashableType>::value

我无法使用 boost 库。

【问题讨论】:

  • this 能解决你的问题吗?
  • 我看过这篇文章,我已经解决了我的那部分问题。问题是如何创建将针对不同类型使用不同 sets 的类。
  • std::conditional_t&lt;is_hashable_v&lt;T&gt;, std::unordered_set&lt;T&gt;, std::set&lt;T&gt;&gt; 怎么样?
  • 看起来不错,谢谢!我试试看。

标签: c++ templates sfinae


【解决方案1】:

如果你有一个is_hashable&lt;T&gt; 类型特征(例如你的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 版本的 trait)。

关于确定哈希性的一些额外讨论,这也很有趣:

Check if type is hashable

在网站上。

【讨论】:

  • 谢谢,但我对元编程很陌生,不知道如何解决我的问题。我需要创建一个包含一些容器的类,但无法同时使用std::setstd::unodered_set。以及如何使用std::conditional 来解决这个问题?
  • 哦,我忘了提到T 类型可能没有== 和(&lt;&gt;)这两个运算符。对于这种类型我需要使用std::unordered_set&lt;T*&gt;,我担心std::conditional可能对我没有帮助。
【解决方案2】:

这是一个完整的工作示例,假设您使用的是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 { };

【讨论】:

  • 谢谢!这是我需要的,甚至更多
猜你喜欢
  • 2020-06-21
  • 1970-01-01
  • 2017-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-28
  • 1970-01-01
相关资源
最近更新 更多