vladon
vladon

Reputation: 8401

Deriving from `boost::asio::streambuf`

I'm trying to create my class which is simply public-derived from boost::asio::streambuf with some methods added:

class my_super_streambuf : public boost::asio::streambuf {
public:  
  void my_super_method();
};

But when I simply replace boost::asio::streambuf to my_super_streambuf there is errors occured:

error C2039: 'const_iterator' : is not a member of 'my_super_streambuf'

in

D:\projects\my_super_streambuf\third-party\boost\boost/asio/impl/write.hpp(199) : 
see reference to class template instantiation
'boost::asio::detail::consuming_buffers<boost::asio::const_buffer,
ConstBufferSequence>' being compiled

How can I correctly derive from boost::asio::streambuf?

Upvotes: 1

Views: 698

Answers (2)

Tanner Sansbury
Tanner Sansbury

Reputation: 51961

The issue is not with how one derives from boost::asio::streambuf. Instead, the resulting error is because the compiler is selecting the non-streambuf write(SyncWriteStream&, const ConstBufferSequence&) overload instead of write(SyncWriteStream&, basic_streambuf<Allocator>&). To resolve this, one can explicitly cast an object derived from boost::asio::streambuf to a reference of boost::asio::streambuf when invoking write():

class derived_streambuf
  : public boost::asio::streambuf
{};

// ...

derived_streambuf streambuf;
boost::asio::write(socket, static_cast<boost::asio::streambuf&>(streambuf));

To understand the issue, consider the declarations of the overloaded function in question:

// ConstBufferSequence
template<
    typename SyncWriteStream,
    typename ConstBufferSequence>
std::size_t write(
    SyncWriteStream&,
    const ConstBufferSequence&);

// Streambuf
template<
    typename SyncWriteStream,
    typename Allocator>
std::size_t write(
    SyncWriteStream&,
    basic_streambuf<Allocator>&);

If derived_streambuf is provided as the second argument, the instantiation of the functions would result in:

// ConstBufferSequence
std::size_t write(..., derived_streambuf&);

// Streambuf
std::size_t write(..., basic_streambuf<char>&);

As far as the compiler is concerned, the first is a better match as it is an exact match, and thus it is selected.


Here is a complete example demonstrating code that compiles:

#include <boost/asio.hpp>

// Derive from boost::asio::streambuf.
class derived_streambuf
  : public boost::asio::streambuf
{};

// Helper function to force type.
template <typename Allocator>
boost::asio::basic_streambuf<Allocator>&
as_streambuf(boost::asio::basic_streambuf<Allocator>& streambuf)
{
  return streambuf;
}

int main()
{
  boost::asio::io_service io_service;
  boost::asio::ip::tcp::socket socket(io_service);
  derived_streambuf streambuf;
  boost::asio::write(socket, static_cast<boost::asio::streambuf&>(streambuf));
  boost::asio::write(socket, as_streambuf(streambuf));
}

Upvotes: 3

yangguang1029
yangguang1029

Reputation: 1823

are you sure there is a "const_iterator" as a public member of "boost::asio::streambuf" ?

i tried these code, and it works:

class MyVector : public std::vector<int>{};
int main(int argc, const char * argv[]) {
    MyVector v;
    v.push_back(1);
    for (MyVector::const_iterator iter = v.begin(); iter != v.end(); iter++) {
        cout << *iter << endl;
    }
}

and also these:

class MyBase {
    public:
        typedef int base_int;
};
class MyDerived : public MyBase {};

MyDerived::base_int P = 5;
MyBase::base_int Q = 5;

Upvotes: 0

Related Questions