如何在C++中获取任意 (STL) 输出迭代器的"assignable type"



C++ 标准要求将 std::iterator_traits<OutputIterator> 中的 typedef value_type设置为 void 对于类型为 OutputIterator 的输出迭代器。尽管如此,对于给定的输出迭代器类型 OutputIterator 推断出在形式表达式中o的可接受类型(不引用任何隐式转换)是完全合理的(在我的代码中是绝对必需的)

*it = o

其中it是类型 OutputIterator 的对象。

理想情况下,我想使用 TMP 定义一个模板类my_iterator_traits它定义了一个 typedef assignable_type,这样my_iterator_traits<OutputIterator>::assignable_type就会等于 decltype( o ) 。有什么建议如何实现这一目标吗?

如果我通过定义模板专用化来枚举所有可能的 STL 迭代器类型,我什至不知道如何实现这一点。例如,以下代码无法编译,因为编译器无法推断模板参数T

template <typename Iterator> struct my_iterator_traits;
//[...]
//Does NOT compile, compiler cannot deduce type T
template <typename T> struct my_iterator_traits<std::vector<T>::iterator>
{
    typedef typename std::vector<T>::value_type assignable_type;
    //Another option, but I think not so clean:
    //typedef T assignable_type;
};

编辑:这是我遇到问题的情况的草图(没有上下文)。建议要在二进制级别编辑容器的元素。对象first是一个(输入)迭代器,它允许我访问已知大小(在本例中为 2 字节)的输入元素。我想通过接受单字节(输出)对象的输出迭代器result将它们写入"二进制输出"。即,我不想指定输出迭代器的"单字节类型"应该是什么。(准-)法典:

const typename my_iterator_traits<OutputIterator>::assignable_type* ptr;
for( size_type i = 0; i < n; ++i, ++first )
{
    ptr = reinterpret_cast<const typename my_iterator_traits<OutputIterator>::assignable_type*>( &( *first ) );
    *result = ptr[0]; ++result;
    *result = ptr[1]; ++result;
}

我担心如果没有reinterpret_cast,可能会出现某些隐式转换会改变二进制结构的情况。我只想将位复制到目标,无论目标是什么以及如何通过输出迭代器提供的抽象接口访问它。唯一的要求是可以通过输出迭代器逐字节访问目标。

您的问题一般无法回答。

例如,下面是一个输出迭代器,虽然它在技术上只需要一种类型来operator=,但实际上采用任何类型:

template<class OS>
struct ostream_proxy {
  void* v;
  void(*f)(void*, OS&);
  template<class O>
  friend O& operator<<(O& o, ostream_proxy p) {
    p.f(p.v, o);
    return o;
  }
  template<class X, class pX = typename std::decay_t<X>::type*>
  ostream_proxy( X&& x ):
    v(&x),
    f(
      [](void* px, OS& os) {
        os << &static_cast<pX>(px);
      }
    )
  {}
};
template<class OS>
std::ostream_iterator<ostream_proxy<OS>> it_out(OS& os) {
  return {os};
}
template<class OS, class CharT>
std::ostream_iterator<ostream_proxy<OS>> it_out(OS& os, const CharT* delim) {
  return {os, delim};
}

现在上面我很懒,我用代理类型使用了std::ostream_iterator。 但是,输出迭代器上的operator=重载或成为template运算符是合法的。 如果是这种情况,则输出迭代器不会接受"一种没有转换的类型"。

(一个不那么懒惰/黑客的版本会重新实现ostream_iterator<>有一个template operator=,并且只写出任何类型。 在我看来,这将是std::ostream_iterator<void>的一个很好的实现,就像std::less<void>(又名std::less<>)一样)。

检查是否有办法将给定类型分配给迭代器很容易,但在一般情况下,确定哪种类型涉及"无转换"是不可能的。 在特定情况下,有无数的黑客攻击。

像大多数"给定一个函数对象,给我它的签名"一样,这个问题假设有一个固定类型,或者应该有一个固定类型,涉及。 输出迭代器具有可用于加载它们的有效表达式,而不是特定类型。

最新更新