STL容器迭代器的模板专业化? [英] Template specialization for iterators of STL containers?

查看:216
本文介绍了STL容器迭代器的模板专业化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一个类似于 std :: to_string 的模板函数,它适用于基本类型以及STL容器的迭代器。但我不知道如何编写模板足够具体到足以识别迭代器。

I am trying to write a template function similar to std::to_string that works for basic types as well as iterators of STL containers. But I am not sure how to write the templates specific enough to identify just the iterators.

我试图到目前为止尝试使用在STL容器中的迭代器 typedef

What I tried so far is to try to use the iterator typedef in STL containers

  template<typename... Args, template <typename...> class Container>
  static string to_string(typename Container<Args...>::iterator s) { ...

一个最小的例子如下。代码编译但模板函数 My :: to_string 无法匹配上述签名,并且处理 std :: set< int> :: iterator 作为默认类型。

A minimal example is attached below. The code compiles but the template function My::to_string fails to match the above signature, and treated std::set<int>::iterator as a default type.

我的问题是如何正确地写一个通用的方式, My :: to_string 可以接受迭代器,但不要将迭代器与其他标准模板类型 std :: string 混淆。

My question is how to write this correctly in a generic manner, so that the template function My::to_string can pickup iterators, but do not confuse iterators with other standard template types like std::string.

提前感谢。

#include <set>
#include <iostream>
using namespace std;

class My{
  //base case
  template<typename T>
  static string to_string(const T& t) {
    return "basic ";
  }

  //specialization for string
  template <typename Char, typename Traits, typename Alloc>
  static string to_string(const std::basic_string<Char, Traits, Alloc>& s) {
    return (string)s;
  }

  //Problem line: how to write specialization for iterators of standard containers?
  template<typename... Args, template <typename...> class Container>
  static string to_string(typename Container<Args...>::iterator s) {
    return "itor ";
  }
};

int main() {
  int i =  2;
  string str = "Hello";
  set<int> s;
  s.insert(i);
  cout << to_string(i) << ", " << str << ", "
       << to_string(s.begin()) << endl;   //didn't get captured by iterator spec.
}

输出:

basic, Hello, basic

所需输出:

basic, Hello, itor


推荐答案

如果你只关心参数的 iterator-ness ,而不是容器的类型,那么你可以SFINAE重载

If you only care about the iterator-ness of the parameter, and not the type of the container, then you can SFINAE out the other overload.

首先使 is_iterator trait,如此回答

First make an is_iterator trait, as shown in this answer:

template <typename T>
struct sfinae_true : std::true_type {};

struct is_iterator_tester {
    template <typename T>
    static sfinae_true<typename std::iterator_traits<T>::iterator_category> test(int);

    template <typename>
    static std::false_type test(...);
};

template <typename T>
struct is_iterator : decltype(is_iterator_tester::test<T>(0)) {};



现在SFINAE错误的重载取决于类型是否是迭代器:

Now SFINAE out the wrong overload depending on whether the type is an iterator:

//base case
template<typename T>
static std::enable_if_t<!is_iterator<T>::value, string> to_string(const T& t) {
  return "basic ";
}

//specialization for string
template <typename Char, typename Traits, typename Alloc>
static string to_string(const std::basic_string<Char, Traits, Alloc>& s) {
  return (string)s;
}

//Problem line: how to write specialization for iterators of standard containers?
template<typename T>
static std::enable_if_t<is_iterator<T>::value, string> to_string(const T& s) {
  return "itor ";
}

演示

这篇关于STL容器迭代器的模板专业化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆