I am hoping for some guidance regarding C++ templates. I have been using the boost::asio
library for communication over TCP. Thus far, I have been using storage containers built into the boost::asio library. For instance:
boost::array<char, 128> buf;
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
To read from a socket, I simply wrap a buffer of type boost::asio::buffer
around my boost::array
object. This works fine, but now I'd like to work in the reverse direction. That is, I'd like to write back into the socket, pulling data from some custom storage classes I already have. My question is, how do I make sense of the template type requirements required to be wrappable by boost::asio::buffer, or more generally, the parameter type specified by:
template<typename ConstBufferSequence>
std::size_t send(
const ConstBufferSequence & buffers
);
The API lists the requirements of a ConstBufferSequence, but I can't make heads or tails of this. Can somebody help me understand? What methods would the type I want to pass to the "send" function need to expose?
boost::asio::buffer
returns objects implementing the ConstBufferSequence
and MutableBufferSequence
concepts; it doesn't expect you to implement them. The concrete types you're allowed to pass to buffer
are listed here.
Although boost::asio::buffer works OK if you have a contiguous set of bytes in memory that you want to use as a buffer, if you are using scatter/gather I/O --or in particular if you are using gather writes (scatter reads are much less common), you do need to have an object that behaves like a ConstBufferSequence.
[If Concepts had made it into the standard [sigh], you would need an object that implements the ConstBufferSequence concept]
Here is a snippet of code from the Codecs::DataDestination class in QuickFAST (http:://www.quickfast.org) that implements ConstBufferSequence:
class DataDestination
{
/// @brief Support for asio gather writes: forward iterator through buffers
///
/// The intent is for DataDestination to conform to the asio::ConstBufferSequence concept.
/// This would allow it to be passed directly to the asio::write(v)
/// Note the implication that if asynch writes are used the DataDestination must
/// remain intact until the write completes.
class const_iterator
{
public:
/// @brief construct an iterator pointing into a DataDestination
/// @param destination is the buffer-container
/// @param position is the starting position for the iterator.
const_iterator(const DataDestination & destination, size_t position)
: destination_(destination)
, position_(position)
{
}
/// @brief Point iterator to next buffer (preincrement)
const_iterator & operator ++()
{
if(position_ < destination_.size())
{
++position_;
}
return *this;
}
/// @brief Point iterator to next buffer (postincrement)
const_iterator operator ++(int)
{
const_iterator result(*this);
if(position_ < destination_.size())
{
++position_;
}
return result;
}
/// @brief dereference the iterator to find the actual buffer
boost::asio::const_buffer operator * () const
{
const WorkingBuffer & buffer(destination_[position_]);
return boost::asio::const_buffer(buffer.begin(), buffer.size());
}
/// @brief dereference the iterator to find the actual buffer
boost::asio::const_buffer operator -> () const
{
const WorkingBuffer & buffer(destination_[position_]);
return boost::asio::const_buffer(buffer.begin(), buffer.size());
}
/// @brief compare iterators.
/// @param rhs is the iterator to which this should be compared.
bool operator == (const const_iterator & rhs) const
{
return position_ == rhs.position_;
}
/// @brief compare iterators.
/// @param rhs is the iterator to which this should be compared.
bool operator != (const const_iterator & rhs) const
{
return position_ != rhs.position_;
}
private:
const_iterator & operator=(const_iterator &); // no autogenerated assignment
private:
const DataDestination & destination_;
size_t position_;
};
/// @brief return iterator pointing to the first buffer.
const_iterator begin()const
{
return const_iterator(*this, 0);
}
/// @brief return iterator pointing past the last buffer
const_iterator end() const
{
return const_iterator(*this, used_);
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With