c++ - 为 T 类型的容器专门化一个模板

标签 c++ templates containers specialization partial-specialization

鉴于我有一个模板设置可以在诸如...

template<typename T>
class SimpleTemplate
{
private:
  T m_obj;
public:
  void operator()() { m_obj.DoSomething(); }
};

我想以同样的方式处理我有一个 T 类型集合的情况。我目前有一个像这样的 vector 模板设置......
template<typename T>
class SimpleTemplate<std::vector<T>>
{
private:
  std::vector<T> m_collection;
public:
  void operator()()
  {
    for (auto&& obj : m_collection) obj.DoSomething();
  }
};

现在我还想支持集合、unordered_sets 等等。我可以为每个集合编写一个模板,但我觉得这应该是模板的完美工作,只是我不知道应该如何编写,或者甚至可以吗?
我可以做类似 template<typename C<T>> 的事情吗? ?

最佳答案

正如 Geoffroy 所提到的,您可以使用特征来检测 T可以迭代。然后您可以使用它来选择正确的特化。

因此,从 Jarod42 here 显示的“is_iterable”特征开始:

// Code by Jarod42 (https://stackoverflow.com/a/29634934).
#include <iterator>
#include <type_traits>

namespace detail
{
    // To allow ADL with custom begin/end
    using std::begin;
    using std::end;

    template <typename T>
    auto is_iterable_impl(int)
    -> decltype (
        begin(std::declval<T&>()) != end(std::declval<T&>()), // begin/end and operator !=
        void(), // Handle evil operator ,
        ++std::declval<decltype(begin(std::declval<T&>()))&>(), // operator ++
        void(*begin(std::declval<T&>())), // operator*
        std::true_type{});

    template <typename T>
    std::false_type is_iterable_impl(...);

}

template <typename T>
using is_iterable = decltype(detail::is_iterable_impl<T>(0));

这会给你一个 is_iterable<T>继承自 std::true_type 的特征或 std::false_type .现在将其与 SFINAE 结合使用以创建两个特化:
template <class T, bool = is_iterable<T>::value>
class SimpleTemplate;

template <class T>
class SimpleTemplate<T, false> {
  private:
    T m_obj;

  public:
    SimpleTemplate (T obj) : m_obj(std::move(obj)) { }

    void operator() () { m_obj.DoSomething(); }
};

template <class T>
class SimpleTemplate<T, true> {
  private:
    T m_collection;

  public:
    SimpleTemplate (T obj) : m_collection(std::move(obj)) { }

    void operator() () {
      for (auto && obj : m_collection) { obj.DoSomething(); }
    }
};

因为对于任何给定的 T 两个部分特化是互斥的,你不会得到任何关于歧义的错误。

编辑:将第二个模板参数更改为 bool 而不是类。这使得在不需要默认行为的情况下完全专门化它变得简单。

例如。为 std::string , 其中 is_iterable是的,只需执行以下操作。请注意,我向 SimpleTemplate 添加了构造函数,否则我无法获得完整的特化来继承基类的构造函数。
template <>
class SimpleTemplate<std::string, true>
    : public SimpleTemplate<std::string, false> {
  // Inherit constructor.
  using base = SimpleTemplate<std::string, false>;
  using base::base;
};

关于c++ - 为 T 类型的容器专门化一个模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60608588/

相关文章:

c++ - 防止 gcc 在包含搜索路径上搜索当前目录 "-I-"选项

c++ - VirtualQueryEx 与 ReadProcessMemory 的关系

c++ - 复制构造函数 : deep copying an abstract class

c++ - 与 decltype 一起使用时的函数类型

c++ - 将 std::get 与枚举类一起使用时需要 static_cast

c++ - cpp 文件的函数模板特化语法

c++ - 将可变参数模板参数包解压到函数签名中

C++ 本地容器

c++ - 在实现 Trees/Heaps/Lists 等时,为什么 `find` 方法应该返回对象的迭代器而不是对象本身?

c++ - 有没有办法 Hook std 容器的插入和删除操作?