使用boost iostreams过滤器(关闭和不可复制)

时间:2011-01-12 18:09:22

标签: c++ boost c++11 boost-iostreams

在询问question about crypto++之后,我尝试使用boost iostreams来实现它。我制作了以下代码:

#include <iostream>
#include <cryptopp/sha.h>
#include <algorithm>
#include <boost/array.hpp>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/operations.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/file.hpp>

template<typename hash>
class sha_output_filter : public boost::iostreams::output_filter
{
  hash _hash;
  char _digest[hash::DIGESTSIZE];
public:
  typedef char                                 char_type;
  typedef boost::iostreams::output_filter_tag  category;

  sha_output_filter() {}
  //sha_output_filter(const sha_output_filter &) = delete;
  sha_output_filter &operator=(const sha_output_filter &) = delete;

  template<typename Sink>
  bool put (Sink &dest, int c)
  {
    std::cout << "put" << std::endl;
    char _c = c;
    _hash.Update ((const byte *)&_c, 1);
    boost::iostreams::put (dest, c);
  }

  template<typename Source>
  void close (Source &src)
  {
    std::cout << "close" << std::endl;
    _hash.Final(_digest);
  }

  boost::array<char, hash::DIGESTSIZE> digest() {
    boost::array<char, hash::DIGESTSIZE> tmp;
    std::copy(_digest, _digest + hash::DIGESTSIZE, tmp.begin() );
    return tmp;
  }
};

int main()
{
  sha_output_filter<CryptoPP::SHA1> outf;
  boost::iostreams::filtering_ostream out;
  out.set_auto_close (true);
  out.push(outf);
  out.push(boost::iostreams::file_sink("my_file.txt"));
  std::cout << "write" << std::endl;
  out.write("123\n", 4);
  out.pop ();
  out.pop ();
  boost::iostreams::file_sink hash_out("hash.txt");
  boost::array<char, CryptoPP::SHA1::DIGESTSIZE> digest = outf.digest();
  hash_out.write(digest.begin (), CryptoPP::SHA1::DIGESTSIZE);
}

问题没有。 1:如果我使sha_output_filter不可复制,尽管文档说明"if T is a standard stream or stream buffer type, by using the templated overload of push taking a non-const reference."但是如果我取消注释行,则它不起作用:

In file included from /usr/include/boost/iostreams/traits.hpp:31:0,
                 from /usr/include/boost/iostreams/detail/dispatch.hpp:17,
                 from /usr/include/boost/iostreams/flush.hpp:17,
                 from /usr/include/boost/iostreams/close.hpp:18,
                 from /usr/include/boost/iostreams/operations.hpp:16,
                 from test.cpp:6:
test.cpp: In function ‘T boost::iostreams::detail::wrap(const T&, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’:
/usr/include/boost/iostreams/stream_buffer.hpp:94:5:   instantiated from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’
/usr/include/boost/iostreams/chain.hpp:257:60:   instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’
/usr/include/boost/iostreams/chain.hpp:216:1:   instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’
/usr/include/boost/iostreams/chain.hpp:496:7:   instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int]’
/usr/include/boost/iostreams/chain.hpp:484:1:   instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’
test.cpp:51:16:   instantiated from here
test.cpp:20:3: error: deleted function ‘sha_output_filter<hash>::sha_output_filter(const sha_output_filter<hash>&) [with hash = CryptoPP::SHA1, sha_output_filter<hash> = sha_output_filter<CryptoPP::SHA1>]’
/usr/include/boost/iostreams/detail/wrap_unwrap.hpp:53:14: error: used here
In file included from /usr/include/boost/iostreams/detail/streambuf/indirect_streambuf.hpp:23:0,
                 from /usr/include/boost/iostreams/stream_buffer.hpp:22,
                 from /usr/include/boost/iostreams/chain.hpp:35,
                 from /usr/include/boost/iostreams/filtering_streambuf.hpp:17,
                 from /usr/include/boost/iostreams/filtering_stream.hpp:22,
                 from test.cpp:7:
test.cpp: In constructor ‘boost::iostreams::detail::concept_adapter<T>::concept_adapter(const T&) [with T = sha_output_filter<CryptoPP::SHA1>]’:
/usr/include/boost/iostreams/detail/streambuf/indirect_streambuf.hpp:187:5:   instantiated from ‘void boost::iostreams::detail::indirect_streambuf<T, Tr, Alloc, Mode>::open(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’
/usr/include/boost/iostreams/stream_buffer.hpp:106:13:   instantiated from ‘void boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::open_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’
/usr/include/boost/iostreams/stream_buffer.hpp:94:5:   instantiated from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’
/usr/include/boost/iostreams/chain.hpp:257:60:   instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’
/usr/include/boost/iostreams/chain.hpp:216:1:   instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’
/usr/include/boost/iostreams/chain.hpp:496:7:   instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int]’
/usr/include/boost/iostreams/chain.hpp:484:1:   instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’
test.cpp:51:16:   instantiated from here
test.cpp:20:3: error: deleted function ‘sha_output_filter<hash>::sha_output_filter(const sha_output_filter<hash>&) [with hash = CryptoPP::SHA1, sha_output_filter<hash> = sha_output_filter<CryptoPP::SHA1>]’
/usr/include/boost/iostreams/detail/adapter/concept_adapter.hpp:67:48: error: used here
test.cpp: In copy constructor ‘boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >::concept_adapter(const boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >&)’:
/usr/include/boost/iostreams/detail/adapter/concept_adapter.hpp:38:23:   instantiated from ‘void boost::iostreams::detail::optional<T>::reset(const T&) [with T = boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >]’
/usr/include/boost/iostreams/detail/streambuf/indirect_streambuf.hpp:187:5:   instantiated from ‘void boost::iostreams::detail::indirect_streambuf<T, Tr, Alloc, Mode>::open(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’
/usr/include/boost/iostreams/stream_buffer.hpp:106:13:   instantiated from ‘void boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::open_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’
/usr/include/boost/iostreams/stream_buffer.hpp:94:5:   instantiated from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’
/usr/include/boost/iostreams/chain.hpp:257:60:   instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’
/usr/include/boost/iostreams/chain.hpp:216:1:   instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’
/usr/include/boost/iostreams/chain.hpp:496:7:   instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int]’
/usr/include/boost/iostreams/chain.hpp:484:1:   instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’
test.cpp:51:16:   instantiated from here
test.cpp:20:3: error: deleted function ‘sha_output_filter<hash>::sha_output_filter(const sha_output_filter<hash>&) [with hash = CryptoPP::SHA1, sha_output_filter<hash> = sha_output_filter<CryptoPP::SHA1>]’
/usr/include/boost/iostreams/detail/adapter/concept_adapter.hpp:38:23: error: used here
In file included from /usr/include/boost/iostreams/detail/streambuf/direct_streambuf.hpp:26:0,
                 from /usr/include/boost/iostreams/stream_buffer.hpp:21,
                 from /usr/include/boost/iostreams/chain.hpp:35,
                 from /usr/include/boost/iostreams/filtering_streambuf.hpp:17,
                 from /usr/include/boost/iostreams/filtering_stream.hpp:22,
                 from test.cpp:7:
/usr/include/boost/iostreams/detail/optional.hpp: In member function ‘void boost::iostreams::detail::optional<T>::reset(const T&) [with T = boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >]’:
/usr/include/boost/iostreams/detail/optional.hpp:100:9: note: synthesized method ‘boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >::concept_adapter(const boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >&)’ first required here

然而boost::ref有效。


问题没有。 2.如何关闭流?调试输出是:

write
put
put
put
put

1 个答案:

答案 0 :(得分:5)

第一个问题是您的sha_output_filter不符合使用push的非常量重载的要求,因为它不是来自std::istreamstd::ostreamstd::streambuf,因此它不被归类为标准流或流缓冲类型 这可以从编译器的第一个消息中推断出来

  

test.cpp:在函数'T boost :: iostreams :: detail :: wrap(const T&amp;,typename boost :: disable_if&lt; boost :: iostreams :: is_std_io&lt; T&gt;&gt; :: type *)[使用T = sha_output_filter&lt; CryptoPP :: SHA1&gt;,typename boost :: disable_if&lt; boost :: iostreams :: is_std_io&lt; T&gt; &gt; :: type = void]':

表示它可以成功解析boost::disable_if<...>::type,因此它不会禁用此重载。如果查看源代码,您可能会在非const重载上找到enable_if测试。


关于第二个问题,您的过滤器未标记为可关闭,因此Boost库不知道它可以在过滤器上调用close

可以使用

替换category的typedef来解决此问题
struct category : boost::iostreams::output_filter_tag, boost::iostreams::closable_tag {};