简体   繁体   English

丢弃需要 output 迭代器的 function 的 output

[英]Discarding the output of a function that needs an output iterator

Suppose there´sa template function in C++ that does some useful work but also outputs a sequence of values via an output iterator.假设在 C++ 中有一个模板 function 做了一些有用的工作,但也通过 output 迭代器输出一系列值。 Now suppose that that sequence of values sometimes is interesting, but at others is not useful.现在假设该值序列有时很有趣,但有时没有用。 Is there a ready-to-use iterator class in the STL that can be instantiated and passed to the function and will ignore any values the function tries to assign to the output iterator? Is there a ready-to-use iterator class in the STL that can be instantiated and passed to the function and will ignore any values the function tries to assign to the output iterator? To put in another way, send all data to /dev/null?换句话说,将所有数据发送到 /dev/null?

The STL does not provide such an iterator. STL不提供这样的迭代器。 But you could code it yourself (tested that code): 但你可以自己编写代码(测试代码):

struct null_output_iterator : 
    std::iterator< std::output_iterator_tag,
                   null_output_iterator > {
    /* no-op assignment */
    template<typename T>
    void operator=(T const&) { }

    null_output_iterator & operator++() { 
        return *this; 
    }

    null_output_iterator operator++(int) { 
        return *this;
    }

    null_output_iterator & operator*() { return *this; }
};

It doesn't need any data by using itself as the result of operator* . 作为operator*的结果,它不需要使用任何数据。 The result of *it = x; *it = x;的结果*it = x; is not used in the output iterator requirements, so we can give it a return type of void . 在输出迭代器要求中没有使用,所以我们可以给它一个返回类型的void


Edit: Let's go into how this operator* works. 编辑:让我们来看看这个operator*工作原理。 The Standard says in 24.1.2/1 about the requirements of an output iterator that in both these cases: 标准在24.1.2 / 1中说明了输出迭代器的要求,在这两种情况下:

*it = t;
*it++ = t;

That the result of those expressions is not used. 没有使用这些表达式的结果。 That's what makes this work: 这就是使这项工作的原因:

null_output_iterator it;
*it; // returns a null_output_iterator& per definition of the `operator*`.
*it = some_value; // returns void per definition of the templated `operator=`. 

Now we don't need to have any data that we return in operator* : We just use the iterator itself. 现在我们不需要在operator*返回任何数据:我们只使用迭代器本身。 Note that the templated operator= does not overwrite the builtin copy assignment operator. 请注意,模板化运算符=不会覆盖内置复制赋值运算符。 It's still provided. 它仍然提供。

It isn't hard to write one. 写一个并不难。

template<typename T>
class NullOutputIterator
{
public:
    NullOutputIterator() {}
    NullOutputIterator& operator++() { return *this; }
    NullOutputIterator& operator++(int) { return *this; }
    T& operator*() { return m; }
    T* operator->() { return &m; }
private:
    T m;
};

I haven't tested this, and there's probably something important missing, but I think this is the idea. 我没有对此进行测试,可能还有一些重要的缺失,但我认为这是个主意。

Do you have Boost available? 你有Boost可用吗? If so you could use a function_output_iterator wrapping an empty function. 如果是这样,你可以使用一个function_output_iterator包装的空函数。

It's not ideal though. 但这并不理想。 Whatever iterator you use will still need to create an instance of the value_type for return in operator*, even if it then throws it away. 无论你使用什么迭代器,仍然需要在operator *中为return返回创建一个value_type实例,即使它然后抛出它。

I based mine on std::back_insert_iterator , but without the container: 我基于std :: back_insert_iterator ,但没有容器:

#include <iterator>

template<typename T>
class NullOutputIter
    : public std::iterator<std::output_iterator_tag,void,void,void,void>
{
public:
    NullOutputIter &operator=(const T &) { return *this; }
    NullOutputIter &operator*() { return *this; }
    NullOutputIter &operator++() { return *this; }
    NullOutputIter operator++(int) { return *this; }
};

This is similar to Johannes's answer, but without the template operator= that takes whatever. 这类似于约翰内斯的答案,但没有模板operator=取任何东西。 I like strong typing; 我喜欢强烈的打字; I want *it = wrong_type_thing to be a compile-time error. 我想*it = wrong_type_thing是编译时错误。 Also this uses void for the various template parameters to std::iterator , like the output iterators in the standard library. 此外,对于std::iterator的各种模板参数,它使用void ,就像标准库中的输出迭代std::iterator一样。

This is also similar to Mark's solution, but (a) it properly inherits from std::iterator and (b) it does not have the unneeded internal state variable. 这也类似于Mark的解决方案,但是(a)它正确地从std::iterator继承而且(b)它没有不需要的内部状态变量。

Updated answer (2022)更新答案 (2022)

With C++17,std::iterator is deprecated.对于 C++17,std::iterator 已弃用。 If you want to avoid a warning, you have to declare the types in the public interface:如果要避免警告,则必须在公共接口中声明类型:

  ///
  /// @brief Allows to discard the output of functions that requires an output iterator
  ///
  template<typename T>
  struct null_output_iterator
  {
    using iterator_category = std::forward_iterator_tag;
    using value_type = T;
    using difference_type = T;
    using pointer = T*;
    using reference = T&;
    ///
    /// @brief No-op assignment
    ///
    void operator=(T const&) {}
    ///
    /// @brief Can be pre-incremented
    ///
    null_output_iterator & operator++()
    {
      return *this;
    }
    ///
    /// @brief Can be post-incremented
    ///
    null_output_iterator operator++(int)
    {
      return *this;
    }
    ///
    /// @brief Can be dereferenced
    ///
    null_output_iterator & operator*()
    {
      return *this;
    }
  };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM