丢弃接受输出迭代器的函数的输出

发布于 2024-07-09 13:11:38 字数 147 浏览 5 评论 0原文

假设 C++ 中有一个模板函数,它执行一些有用的工作,但也通过输出迭代器输出一系列值。 现在假设值的序列有时很有趣,但有时没有用。 STL 中是否有一个现成的迭代器类可以实例化并传递给函数,并且会忽略函数尝试分配给它的任何值? 换句话说,将所有数据发送到/dev/null?

Suppose there´s a template function in C++ that does some useful work but also outputs a sequence of values via an output iterator. Now suppose that the 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 value the function tries to assign to it? To put in another way, send all data to /dev/null?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

回忆凄美了谁 2024-07-16 13:11:38

STL没有提供这样的迭代器。 但您可以自己编写代码(测试该代码):

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

通过使用自身作为 operator* 的结果,它不需要任何数据。 *it = x; 的结果未在输出迭代器要求中使用,因此我们可以为其指定返回类型 void


编辑:让我们来看看这个operator*是如何工作的。 该标准在 24.1.2/1 中提到了在这两种情况下输出迭代器的要求:

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

不使用这些表达式的结果。 这就是它的工作原理:

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=`. 

现在我们不需要在 operator* 中返回任何数据:我们只需使用迭代器本身。 请注意,模板化运算符= 不会覆盖内置复制赋值运算符。 还是提供了。

The STL does not provide such an iterator. 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*. The result of *it = x; is not used in the output iterator requirements, so we can give it a return type of void.


Edit: Let's go into how this operator* works. The Standard says in 24.1.2/1 about the requirements of an output iterator that in both these cases:

*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. Note that the templated operator= does not overwrite the builtin copy assignment operator. It's still provided.

|煩躁 2024-07-16 13:11:38

你有可用的Boost吗? 如果是这样,您可以使用 function_output_iterator 包装一个空函数。

但这并不理想。 无论您使用什么迭代器,仍然需要创建 value_type 的实例以在操作符 * 中返回,即使它随后将其丢弃。

Do you have Boost available? If so you could use a function_output_iterator wrapping an empty function.

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.

︶葆Ⅱㄣ 2024-07-16 13:11:38

写一篇并不难。

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

我还没有测试过这个,可能缺少一些重要的东西,但我认为这就是这个想法。

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.

绝對不後悔。 2024-07-16 13:11:38

我基于 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; }
};

这与 Johannes 的答案类似,但没有接受任何内容的模板 operator= 。 我喜欢强打字; 我希望 *it = false_type_thing 成为编译时错误。 此外,它还使用 void 作为 std::iterator 的各种模板参数,就像标准库中的输出迭代器一样。

这也类似于 Mark 的解决方案,但是 (a) 它正确地继承自 std::iterator 并且 (b) 它没有不需要的内部状态变量。

I based mine on std::back_insert_iterator, but without the container:

#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. I like strong typing; I want *it = wrong_type_thing to be a compile-time error. Also this uses void for the various template parameters to std::iterator, like the output iterators in the standard library.

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.

伤痕我心 2024-07-16 13:11:38

更新答案(2022)

对于 C++17,std::iterator 已弃用。 如果你想避免警告,你必须在公共接口中声明类型:

  ///
  /// @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;
    }
  };

Updated answer (2022)

With C++17,std::iterator is deprecated. 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;
    }
  };
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文