December 18, 2017·5 min read·engineeringcppboostnetworkingtemplates

Boost 1.66 adds HTTP components and a smaller metaprogramming vocabulary

Beast supplies HTTP and WebSocket building blocks on Asio, while Mp11 manipulates type lists through aliases and variadic templates. Both additions target composition without requiring a complete application framework.

An HTTP implementation can manage protocol details without deciding an application's threading and buffer policies. Beast takes that approach in Boost 1.66, supplying message types and protocol algorithms on Boost.Asio. The same release adds Mp11, whose compile-time algorithms operate on lists of types through alias templates. The additions work in very different domains, but both give applications components with explicit composition rules.

The Boost 1.66 release notes date the release to December 18. They credit Beast to Vinnie Falco and Mp11 to Peter Dimov. Asio also changes its interfaces to reflect the Networking TS. These are library changes available to C++11 users, rather than facilities that require a wholesale move to the recently completed C++17 language revision.

I prefer libraries that make their responsibilities clear. In networking code, protocol processing and ownership policy need to fit together, but one library need not dictate the entire application. In generic code, a small collection of type-list operations can be more useful than another layer of custom template machinery.

Beast supplies protocol components on Asio

The versioned Beast introduction describes a header-only library for HTTP/1 and WebSocket using Asio's asynchronous model. Its algorithms can serve client or server roles. The documentation explicitly leaves buffer and thread management decisions to the user.

This is a defined level of abstraction. Beast can provide the basis of a client or server, but it does not claim to be a complete application with those policies already selected. Users of its asynchronous interfaces need familiarity with Asio and concurrent network programming. The protocol library reduces one body of implementation work without making the rest of the application disappear.

Header-only also does not mean a program has no linking requirements. The introduction requires Boost.System for successful linking, with Boost.Coroutine additionally needed when using coroutines. TLS support has an optional OpenSSL dependency. Those requirements belong to this version's documented build model.

The message body is a selectable representation

Beast's message-container documentation describes a message template parameterized by request or response role, body type and field container. The body parameter controls both the representation of the body and the algorithms that transfer buffers to or from it.

A string body is a convenient case, but the library also supplies file bodies and caller-provided buffers. That lets the message model support different storage and transfer policies without forcing every body into one representation. User-defined body types can provide the corresponding requirements where the supplied choices do not fit.

This response construction follows the versioned documentation. It creates a message object and prepares its payload-related fields without starting a network operation.

#include <boost/beast/http.hpp>

namespace http = boost::beast::http;

http::response<http::string_body> make_response()
{
    http::response<http::string_body> response;
    response.version(11);
    response.result(http::status::ok);
    response.body() = "ready";
    response.prepare_payload();
    return response;
}

prepare_payload chooses the appropriate content-length or transfer-encoding treatment from the body. The documentation also permits setting those fields explicitly. The convenience operation therefore participates in the message's protocol representation while leaving the application in control of the message itself.

The message container provides value semantics when its body and field types support them. That qualification matters when choosing a body that owns a file or refers to external storage. A uniform message template does not imply that every representation has identical copying and lifetime properties.

Mp11 works with existing type-list shapes

The Mp11 documentation for 1.66 describes compile-time manipulation of structures containing types. Metafunctions have the form of alias or class templates, while lists have the form of templates whose parameters are types. The library supplies mp_list, but does not require every algorithm input to use that particular container.

For example, std::tuple can be a list for these algorithms. Transforming its element types can produce another tuple without first converting everything into an unrelated representation. A fixed-arity template such as std::pair also fits some operations, but cannot support operations that need a different number of elements.

#include <boost/mp11.hpp>
#include <tuple>
#include <type_traits>

template<class T>
using pointer_to = T*;

using inputs = std::tuple<int, float>;
using pointers = boost::mp11::mp_transform<pointer_to, inputs>;

static_assert(std::is_same<pointers, std::tuple<int*, float*>>::value,
              "transform preserves the tuple list form");

This example uses only the C++11 vocabulary needed for the aliases and assertion. The transformation changes types during compilation. It does not traverse a tuple object at runtime or allocate storage for its elements.

The documentation also uses products of type lists to generate combinations of test cases. That is a more substantial application of the same model. A compile-time product can describe the combinations, while a separate runtime operation invokes a test for each resulting type combination. Keeping those stages distinct makes the mechanism easier to understand than treating all template code as one opaque calculation.

Mp11 also documents deferred evaluation through mp_defer. Its example of a common_type specialization uses that facility so an invalid transformation can result in substitution failure instead of an unconditional error. This is an important distinction for a library utility used inside other templates. Producing the correct type for valid arguments is only part of its contract. The failure path determines whether generic callers can consider alternatives. The example shows why a type-list library needs controls over instantiation as well as algorithms that concatenate or transform lists. An apparently shorter direct alias can lose that behavior when its arguments are unsuitable.

Existing Asio code also encounters interface changes

The release notes say Asio removes service template parameters from its default socket interfaces. Code depending on the older service form can enable it with BOOST_ASIO_ENABLE_OLD_SERVICES. The same section records removal of previously deprecated functions and other updates following the Networking TS. Adopting Beast and upgrading existing Asio code are therefore related but separate pieces of work.

I find the new libraries useful for different reasons. Beast lets protocol handling fit an application's chosen storage and concurrency model. Mp11 gives template code a consistent way to transform existing type-list representations. In both cases, the versioned documentation identifies the composition boundary, including body-dependent value semantics for messages and arity restrictions for type-list templates. Those boundaries explain where a component can replace custom machinery and where the application must still supply its own policy.