Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Boost C++ Application Development  Cookbook
Boost C++ Application Development  Cookbook

Boost C++ Application Development Cookbook: Recipes to simplify your application development , Second Edition

Arrow left icon
Profile Icon Anton Polukhin Alekseevic
Arrow right icon
$54.99
Full star icon Full star icon Full star icon Full star icon Half star icon 4.2 (5 Ratings)
Paperback Aug 2017 438 pages 2nd Edition
eBook
$9.99 $43.99
Paperback
$54.99
Subscription
Free Trial
Renews at $19.99p/m
Arrow left icon
Profile Icon Anton Polukhin Alekseevic
Arrow right icon
$54.99
Full star icon Full star icon Full star icon Full star icon Half star icon 4.2 (5 Ratings)
Paperback Aug 2017 438 pages 2nd Edition
eBook
$9.99 $43.99
Paperback
$54.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
$9.99 $43.99
Paperback
$54.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Boost C++ Application Development Cookbook

Starting to Write Your Application

In this chapter, we will cover:

  • Getting configuration options
  • Storing any value in a container/variable
  • Storing multiple chosen types in a container/variable
  • Using a safer way to work with a container that stores multiple chosen types
  • Returning a value or flag where there is no value
  • Returning an array from a function
  • Combining multiple values into one
  • Binding and reordering function parameters
  • Getting a human-readable type name
  • Using the C++11 move emulation
  • Making a noncopyable class
  • Making a noncopyable but movable class
  • Using C++14 and C++11 algorithms

Introduction

Boost is a collection of C++ libraries. Each library has been reviewed by many professional programmers before being accepted by Boost. Libraries are tested on multiple platforms using many compilers and many C++ standard library implementations. While using Boost, you can be sure that you are using one of the most portable, fast, and reliable solutions that is distributed under a license suitable for commercial and open source projects.

Many parts of Boost have been included into C++11, C++14, and C++17. Furthermore, Boost libraries will be included in the next standard of C++. You will find C++ standard-specific notes in each recipe of this book.

Without a long introduction, let's get started!

In this chapter, we will see some recipes for everyday use. We'll see how to get configuration options from different sources and what can be cooked up using some of the data types introduced by Boost library authors.

Getting configuration options

Take a look at some of the console programs, such as cp in Linux. They all have a fancy help; their input parameters do not depend on any position and have a human-readable syntax. For example:

$ cp --help
Usage: cp [OPTION]... [-T] SOURCE DEST
-a, --archive same as -dR --preserve=all
-b like --backup but does not accept an argument

You can implement the same functionality for your program in 10 minutes. All you need is the Boost.ProgramOptions library.

Getting ready

Basic knowledge of C++ is all you need for this recipe. Remember that this library is not only a header, so your program has to link against the libboost_program_options library.

How to do it...

Let's start with a simple program that accepts the count of apples and oranges as input and counts the total number of fruits. We want to achieve the following result:

 $ ./our_program.exe --apples=10 --oranges=20
Fruits count: 30

Perform the following steps:

  1. Include the boost/program_options.hpp header and make an alias for the boost::program_options namespace (it is too long to type it!). We would also need an <iostream> header:
#include <boost/program_options.hpp> 
#include <iostream>

namespace opt = boost::program_options;
  1. Now, we are ready to describe our options in the main() function:
int main(int argc, char *argv[])
{
// Constructing an options describing variable and giving
// it a textual description "All options".
opt::options_description desc("All options");

// When we are adding options, first parameter is a name
// to be used in command line. Second parameter is a type
// of that option, wrapped in value<> class. Third parameter
// must be a short description of that option.
desc.add_options()
("apples", opt::value<int>(), "how many apples do
you have")
("oranges", opt::value<int>(), "how many oranges do you
have")
("help", "produce help message")
;
  1. Let's parse the command line:
    // Variable to store our command line arguments.
opt::variables_map vm;

// Parsing and storing arguments.
opt::store(opt::parse_command_line(argc, argv, desc), vm);

// Must be called after all the parsing and storing.
opt::notify(vm);
  1. Let's add some code for processing the help option:
    if (vm.count("help")) {
std::cout << desc << "\n";
return 1;
}
  1. Final step. Counting fruits may be implemented in the following way:
    std::cout << "Fruits count: "
<< vm["apples"].as<int>() + vm["oranges"].as<int>()
<< std::endl;

} // end of `main`

Now, if we call our program with the help parameter, we'll get the following output:

All options: 
--apples arg how many apples do you have
--oranges arg how many oranges do you have
--help produce help message

As you can see, we do not provide a type for the help option's value, because we do not expect any values to be passed to it.

How it works...

This example is pretty simple to understand from code and comments. Running it produces the expected result:

 $ ./our_program.exe --apples=100 --oranges=20
Fruits count: 120

There's more...

The C++ standard adopted many Boost libraries; however, you won't find Boost.ProgramOptions even in C++17. Currently, there's no plan to adopt it into C++2a.

The ProgramOptions library is very powerful and has many features. Here's how to:

  • Parse configuration option values directly into a variable and make that option a required one:
    int oranges_var = 0;
desc.add_options()
// ProgramOptions stores the option value into
// the variable that is passed by pointer. Here value of
// "--oranges" option will be stored into 'oranges_var'.
("oranges,o", opt::value<int>(&oranges_var)->required(),
"oranges you have")
  • Get some mandatory string option:
        // 'name' option is not marked with 'required()',
// so user may not provide it.
("name", opt::value<std::string>(), "your name")
  • Add short name for apple, set 10 as a default value for apples:
        // 'a' is a short option name for apples. Use as '-a 10'.
// If no value provided, then the default value is used.
("apples,a", opt::value<int>()->default_value(10),
"apples that you have");
  • Get the missing options from the configuration file:
    opt::variables_map vm;

// Parsing command line options and storing values to 'vm'.
opt::store(opt::parse_command_line(argc, argv, desc), vm);

// We can also parse environment variables. Just use
// 'opt::store with' 'opt::parse_environment' function.

// Adding missing options from "apples_oranges.cfg" config file.
try {
opt::store(
opt::parse_config_file<char>("apples_oranges.cfg", desc),
vm
);
} catch (const opt::reading_file& e) {
std::cout << "Error: " << e.what() << std::endl;
}
The configuration file syntax differs from the command-line syntax. We do not need to place minuses before the options. So, our apples_oranges.cfg file must look like this:
oranges=20
  • Validate that all the required options were set:
    try {
// `opt::required_option` exception is thrown if
// one of the required options was not set.
opt::notify(vm);

} catch (const opt::required_option& e) {
std::cout << "Error: " << e.what() << std::endl;
return 2;
}

If we combine all the mentioned tips into a single executable, then its help command will produce this output:

$ ./our_program.exe --help
All options:
-o [ --oranges ] arg oranges that you have
--name arg your name
-a [ --apples ] arg (=10) apples that you have
--help produce help message

Running it without a configuration file will produce the following output:

$ ./our_program.exe
Error: can not read options configuration file 'apples_oranges.cfg'
Error: the option '--oranges' is required but missing

Running the program with oranges=20 in the configuration file will generate ++, because the default value for apples is 10:

$ ./our_program.exe
Fruits count: 30

See also

Storing any value in a container/variable

If you have been programming in Java, C#, or Delphi, you will definitely miss the ability of creating containers with the Object value type in C++. The Object class in those languages is a basic class for almost all types, so you are able to assign almost any value to it at any time. Just imagine how great it would be to have such a feature in C++:

typedef std::unique_ptr<Object> object_ptr; 

std::vector<object_ptr> some_values;
some_values.push_back(new Object(10));
some_values.push_back(new Object("Hello there"));
some_values.push_back(new Object(std::string("Wow!")));

std::string* p = dynamic_cast<std::string*>(some_values.back().get());
assert(p);
(*p) += " That is great!\n";
std::cout << *p;

Getting ready

We'll be working with the header-only library. The basic knowledge of C++ is all you need for this recipe.

How to do it...

Boost offers a solution, the Boost.Any library, that has an even better syntax:

#include <boost/any.hpp> 
#include <iostream>
#include <vector>
#include <string>

int main() {
std::vector<boost::any> some_values;
some_values.push_back(10);
some_values.push_back("Hello there!");
some_values.push_back(std::string("Wow!"));

std::string& s = boost::any_cast<std::string&>(some_values.back());
s += " That is great!";
std::cout << s;
}

Great, isn't it? By the way, it has an empty state, which could be checked using the empty() member function (just like in standard library containers).

You can get the value from boost::any using two approaches:

void example() {
boost::any variable(std::string("Hello world!"));

// Following method may throw a boost::bad_any_cast exception
// if actual value in variable is not a std::string.
std::string s1 = boost::any_cast<std::string>(variable);

// Never throws. If actual value in variable is not a std::string
// will return an NULL pointer.
std::string* s2 = boost::any_cast<std::string>(&variable);
}

How it works...

The boost::any class just stores any value in it. To achieve this, it uses the type erasure technique (close to what Java or C# does with all types). To use this library you do not really need to know its internal implementation in detail, but here's a quick glance at the type erasure technique for the curious.

On the assignment of some variable of type T, Boost.Any instantiates a holder<T> type that may store a value of the specified type T and is derived from some base-type placeholder:

template<typename ValueType>
struct holder : public placeholder {
virtual const std::type_info& type() const {
return typeid(ValueType);
}
ValueType held;
};

A placeholder type has virtual functions for getting std::type_info of a stored type T and for cloning a stored type:

struct placeholder {
virtual ~placeholder() {}
virtual const std::type_info& type() const = 0;
};

boost::any stores ptr-- a pointer to placeholder. When any_cast<T>() is used, boost::any checks that calling ptr->type() gives std::type_info equal to typeid(T) and returns static_cast<holder<T>*>(ptr)->held.

There's more...

Such flexibility never comes without any cost. Copy constructing, value constructing, copy assigning, and assigning values to instances of boost::any do dynamic memory allocation; all the type casts do RunTime Type Information (RTTI) checks; boost::any uses virtual functions a lot. If you are keen on performance, the next recipe will give you an idea of how to achieve almost the same results without dynamic allocations and RTTI usage.

boost::any makes use of rvalue references but can not be used in constexpr.

The Boost.Any library was accepted into C++17. If your compiler is C++17 compatible and you wish to avoid using Boost for any, just replace the boost namespace with namespace std and include <any> instead of <boost/any.hpp>. Your standard library implementation may work slightly faster if you are storing tiny objects in std::any.

std::any has the reset() function instead of clear() and has_value() instead of empty(). Almost all exceptions in Boost derived from the std::exception class or from its derivatives, for example, boost::bad_any_cast is derived from std::bad_cast. It means that you can catch almost all Boost exceptions using catch (const std::exception& e).

See also

  • Boost's official documentation may give you some more examples; it can be found at http://boost.org/libs/any
  • The Using a safer way to work with a container that stores multiple chosen types recipe for more info on the topic

Storing multiple chosen types in a container/variable

C++03 unions can only hold extremely simple types called Plain Old Data (POD). For example in C++03, you cannot store std::string or std::vector in a union.

Are you aware of the concept of unrestricted unions in C++11? Let me tell you about it briefly. C++11 relaxes requirements for unions, but you have to manage the construction and destruction of non POD types by yourself. You have to call in-place construction/destruction and remember what type is stored in a union. A huge amount of work, isn't it?

Can we have an unrestricted union like variable in C++03 that manages the object lifetime and remembers the type it has?

Getting ready

We'll be working with the header-only library, which is simple to use. Basic knowledge of C++ is all you need for this recipe.

How to do it...

Let me introduce the Boost.Variant library to you.

  1. The Boost.Variant library can store any of the types specified at compile time. It also manages in-place construction/destruction and even does not even require the C++11 standard:
#include <boost/variant.hpp>
#include <iostream>
#include <vector>
#include <string>

int main() {
typedef boost::variant<int, const char*, std::string> my_var_t;
std::vector<my_var_t> some_values;
some_values.push_back(10);
some_values.push_back("Hello there!");
some_values.push_back(std::string("Wow!"));

std::string& s = boost::get<std::string>(some_values.back());
s += " That is great!\n";
std::cout << s;
}

Great, isn't it?

  1. Boost.Variant has no empty state, but has an empty() function which is useless and always returns false. If you need to represent an empty state, just add some simple type at the first position of the types supported by the Boost.Variant library. When Boost.Variant contains that type, interpret it as an empty state. Here is an example in which we will use a boost::blank type to represent an empty state:
void example1() {
// Default constructor constructs an instance of boost::blank.
boost::variant<
boost::blank, int, const char*, std::string
> var;

// 'which()' method returns an index of a type
// currently held by variant.
assert(var.which() == 0); // boost::blank

var = "Hello, dear reader";
assert(var.which() != 0);
}
  1. You can get a value from a variant using two approaches:
void example2() {
boost::variant<int, std::string> variable(0);

// Following method may throw a boost::bad_get
// exception if actual value in variable is not an int.
int s1 = boost::get<int>(variable);

// If actual value in variable is not an int will return NULL.
int* s2 = boost::get<int>(&variable);
}

How it works...

The boost::variant class holds an array of bytes and stores values in that array. The size of the array is determined at compile time by applying sizeof() and functions to get alignment to each of the template types. On assignment, or construction of boost::variant, the previous values are in-place destructed and new values are constructed on top of the byte array, using the placement new.

There's more...

The Boost.Variant variables usually do not dynamically allocate memory, and they do not require RTTI to be enabled. Boost.Variant is extremely fast and used widely by other Boost libraries. To achieve maximum performance, make sure that there is a simple type in the list of supported types at the first position. boost::variant takes advantage of C++11 rvalue references if they are available on your compiler.

Boost.Variant is part of the C++17 standard. std::variant differs slightly from theboost::variant:

  • std::variant is declared in the <variant> header file rather than in <boost.variant.hpp>
  • std::variant never ever allocates memory
  • std::variant is usable with constexpr
  • Instead of writing boost::get<int>(&variable), you have to write std::get_if<int>(&variable) for std::variant
  • std::variant can not recursively hold itself and misses some other advanced techniques
  • std::variant can in-place construct objects
  • std::variant has index() instead of which()

See also

Using a safer way to work with a container that stores multiple chosen types

Imagine that you are creating a wrapper around some SQL database interface. You decided that boost::any will perfectly match the requirements for a single cell of the database table.

Some other programmer will use your classes, and his/her task would be to get a row from the database and count the sum of the arithmetic types in a row.

This is what such a code would look like:

 

#include <boost/any.hpp> 
#include <vector>
#include <string>
#include <typeinfo>
#include <algorithm>
#include <iostream>

// This typedefs and methods will be in our header,
// that wraps around native SQL interface.
typedef boost::any cell_t;
typedef std::vector<cell_t> db_row_t;

// This is just an example, no actual work with database.
db_row_t get_row(const char* /*query*/) {
// In real application 'query' parameter shall have a 'const
// char*' or 'const std::string&' type? See recipe "Type
// 'reference to string'" for an answer.
db_row_t row;
row.push_back(10);
row.push_back(10.1f);
row.push_back(std::string("hello again"));
return row;
}

// This is how a user will use your classes
struct db_sum {
private:
double& sum_;
public:
explicit db_sum(double& sum)
: sum_(sum)
{}

void operator()(const cell_t& value) {
const std::type_info& ti = value.type();
if (ti == typeid(int)) {
sum_ += boost::any_cast<int>(value);
} else if (ti == typeid(float)) {
sum_ += boost::any_cast<float>(value);
}
}
};

int main() {
db_row_t row = get_row("Query: Give me some row, please.");
double res = 0.0;
std::for_each(row.begin(), row.end(), db_sum(res));
std::cout << "Sum of arithmetic types in database row is: "
<< res << std::endl;
}

If you compile and run this example, it will output a correct answer:

Sum of arithmetic types in database row is: 20.1

Do you remember what your own thoughts were when reading the implementation of operator()? I guess they were, "And what about double, long, short, unsigned, and other types?" The same thoughts will come into the head of a programmer who will use your interface. So, you need to carefully document values stored by your cell_t or use a more elegant solution as described in the following sections.

Getting ready

Reading the previous two recipes is highly recommended if you are not already familiar with the Boost.Variant and Boost.Any libraries.

How to do it...

The Boost.Variant library implements a visitor programming pattern for accessing the stored data, which is much safer than getting values via boost::get<>. This pattern forces the programmer to take care of each type in variant, otherwise the code will fail to compile. You can use this pattern via the boost::apply_visitor function, which takes a visitor functional object as the first parameter and a variant as the second parameter. If you are using a pre C++14 compiler, then visitor functional objects must derive from the boost::static_visitor<T> class, where T is a type being returned by a visitor. A visitor object must have overloads of operator() for each type stored by a variant.

Let's change the cell_t type to boost::variant<int, float, string> and modify our example:

#include <boost/variant.hpp> 
#include <vector>
#include <string>
#include <iostream>

// This typedefs and methods will be in header,
// that wraps around native SQL interface.
typedef boost::variant<int, float, std::string> cell_t;
typedef std::vector<cell_t> db_row_t;

// This is just an example, no actual work with database.
db_row_t get_row(const char* /*query*/) {
// See recipe "Type 'reference to string'"
// for a better type for 'query' parameter.
db_row_t row;
row.push_back(10);
row.push_back(10.1f);
row.push_back("hello again");
return row;
}

// This is a code required to sum values.
// We can provide no template parameter
// to boost::static_visitor<> if our visitor returns nothing.
struct db_sum_visitor: public boost::static_visitor<double> {
double operator()(int value) const {
return value;
}
double operator()(float value) const {
return value;
}
double operator()(const std::string& /*value*/) const {
return 0.0;
}
};

int main() {
db_row_t row = get_row("Query: Give me some row, please.");
double res = 0.0;
for (auto it = row.begin(), end = row.end(); it != end; ++it) {
res += boost::apply_visitor(db_sum_visitor(), *it);
}

std::cout << "Sum of arithmetic types in database row is: "
<< res << std::endl;
}

How it works...

At compile time, the Boost.Variant library generates a big switch statement, each case of which calls a visitor for a single type from the variant's list of types. At runtime, the index of the stored type is retrieved using which() and jumps to a correct case in switch statement is made. Something like this will be generated for boost::variant<int, float, std::string>:

switch (which()) 
{
case 0 /*int*/:
return visitor(*reinterpret_cast<int*>(address()));
case 1 /*float*/:
return visitor(*reinterpret_cast<float*>(address()));
case 2 /*std::string*/:
return visitor(*reinterpret_cast<std::string*>(address()));
default: assert(false);
}

Here, the address() function returns a pointer to the internal storage of boost::variant<int, float, std::string>.

There's more...

If we compare this example with the first example in this recipe, we'll see the following advantages of boost::variant:

  • We know what types a variable can store
  • If a library writer of the SQL interface adds or modifies a type held by a variant, we'll get a compile-time error instead of incorrect behavior

std::variant from C++17 also supports visitation. Just write std::visit instead of boost::apply_visitor and you're done.

You can download the example code files for all Packt books that you have purchased from your account at http://www.PacktPub.com. If you purchased this book elsewhere, you can visit http://www.PacktPub.com/support, and register to have the files emailed directly to you.

See also

  • After reading some recipes from Chapter 4, Compile-Time Tricks, you'll be able to make generic visitor objects that work correctly even if underlying types change
  • Boost's official documentation contains more examples and a description of some other features of Boost.Variant; it is available at the following link: http://boost.org/libs/variant

Returning a value or flag where there is no value

Imagine that we have a function that does not throw an exception and returns a value or indicates that an error has occurred. In Java or C# programming languages, such cases are handled by comparing a return value from a function value with a null pointer. If the function returned null, then an error has occurred. In C++, returning a pointer from a function confuses library users and usually requires slow dynamic memory allocation.

Getting ready

Only basic knowledge of C++ is required for this recipe.

How to do it...

Ladies and gentlemen, let me introduce you to the Boost.Optional library using the following example:

The try_lock_device() function tries to acquire a lock for a device and may succeed or not, depending on different conditions (in our example it depends on some try_lock_device_impl() function call):

#include <boost/optional.hpp>
#include <iostream>

class locked_device {
explicit locked_device(const char* /*param*/) {
// We have unique access to device.
std::cout << "Device is locked\n";
}

static bool try_lock_device_impl();

public:
void use() {
std::cout << "Success!\n";
}

static boost::optional<locked_device> try_lock_device() {
if (!try_lock_device_impl()) {
// Failed to lock device.
return boost::none;
}

// Success!
return locked_device("device name");
}

~locked_device(); // Releases device lock.
};

The function returns the boost::optional variable that can be converted to a bool. If the returned value is equal to true, then the lock is acquired and an instance of a class to work with the device can be obtained by dereferencing the returned optional variable:

int main() { 
for (unsigned i = 0; i < 10; ++i) {
boost::optional<locked_device> t
= locked_device::try_lock_device();

// optional is convertible to bool.
if (t) {
t->use();
return 0;
} else {
std::cout << "...trying again\n";
}
}

std::cout << "Failure!\n";
return -1;
}

This program will output the following:

...trying again
...trying again
Device is locked
Success!
The default constructed optional variable is convertible to false and must not be dereferenced, because such an optional does not have an underlying type constructed.

How it works...

boost::optional<T> under the hood has a properly aligned array of bytes where the object of type T can be an in-place constructed. It also has a bool variable to remember the state of the object (is it constructed or not?).

There's more...

The Boost.Optional class does not use dynamic allocation and it does not require a default constructor for the underlying type. The current boost::optional implementation can work with C++11 rvalue references but is not usable with constexpr.

If you have a class T that has no empty state but your program logic requires an empty state or uninitialized T, then you have to come up with some workaround. Traditionally, users create some smart pointer to the class T, keep a nullptr in it, and dynamically allocate T if non empty state is required. Stop doing that! Use boost::optional<T> instead. It's a much faster and more reliable solution.

The C++17 standard includes the std::optional class. Just replace <boost/optional.hpp> with <optional> and boost:: with std:: to use the standard version of this class. std::optional is usable with constexpr.

See also

Boost's official documentation contains more examples and describes advanced features of Boost.Optional (like in-place construction). The documentation is available at the following link: http://boost.org/libs/optional.

Returning an array from a function

Let's play a game of guessing! What can you tell about the following function?

char* vector_advance(char* val); 

Should return values be deallocated by the programmer or not? Does the function attempt to deallocate the input parameter? Should the input parameter be zero-terminated, or should the function assume that the input parameter has a specified width?

Now, let's make the task harder! Take a look at the following line:

char ( &vector_advance( char (&val)[4] ) )[4];

Do not worry. I've also been scratching my head for half an hour before getting an idea of what is happening here. vector_advance is a function that accepts and returns an array of four elements. Is there a way to write such a function clearly?

Getting ready

Only basic knowledge of C++ is required for this recipe.

How to do it...

We can rewrite the function like this:

#include <boost/array.hpp>

typedef boost::array<char, 4> array4_t;
array4_t& vector_advance(array4_t& val);

Here, boost::array<char, 4> is just a simple wrapper around an array of four char elements.

This code answers all the questions from our first example and is much more readable than the code from the second example.

How it works...

boost::array is a fixed-size array. The first template parameter of boost::array is the element type and the second one is the size of an array. If you need to change the array size at runtime, use std::vector , boost::container::small_vector, boost::container::stack_vector, or boost::container::vector instead.

The boost::array<> class has no handwritten constructors and all its members are public, so the compiler will treat it as a POD type.

There's more...

Let's see some more examples of the usage of boost::array:

#include <boost/array.hpp> 
#include <algorithm>

typedef boost::array<char, 4> array4_t;

array4_t& vector_advance(array4_t& val) {
// C++11 lambda function
const auto inc = [](char& c){ ++c; };

// boost::array has begin(), cbegin(), end(), cend(),
// rbegin(), size(), empty() and other functions that are
// common for standard library containers.
std::for_each(val.begin(), val.end(), inc);
return val;
}

int main() {
// We can initialize boost::array just like an array in C++11:
// array4_t val = {0, 1, 2, 3};
// but in C++03 additional pair of curly brackets is required.
array4_t val = {{0, 1, 2, 3}};

array4_t val_res; // it is default constructible
val_res = vector_advance(val); // it is assignable

assert(val.size() == 4);
assert(val[0] == 1);
/*val[4];*/ // Will trigger an assert because max index is 3

// We can make this assert work at compile-time.
// Interested? See recipe 'Check sizes at compile-time'
assert(sizeof(val) == sizeof(char) * array4_t::static_size);
}

One of the biggest advantages of boost::array is that it does not allocated dynamic memory and provides exactly the same performance as a usual C array. People from the C++ Standard committee also liked it, so it was accepted to the C++11 standard. Try to include the <array> header and check for the availability of std::array. std::array has a better support for usage with constexpr since C++17.

See also

  • Boost's official documentation gives a complete list of the Boost.Array methods with a description of the method's complexity and throw behavior. It is available at the following link: http://boost.org/libs/array.
  • The boost::array function is widely used across recipes; for example, refer to the Binding a value as a function parameter recipe.

Combining multiple values into one

There is a very nice present for those who like std::pair. Boost has a library called Boost.Tuple. It is just like std::pair, but it can also work with triples, quads, and even bigger collections of types.

Getting ready

Only basic knowledge of C++ and a standard library is required for this recipe.

How to do it...

Perform the following steps to combine multiple values into one:

  1. To start working with tuples, you need to include a proper header and declare a variable:
#include <boost/tuple/tuple.hpp> 
#include <string>

boost::tuple<int, std::string> almost_a_pair(10, "Hello");
boost::tuple<int, float, double, int> quad(10, 1.0f, 10.0, 1);
  1. Getting a specific value is implemented via the boost::get<N>() function, where N is a zero-based index of a required value:
#include <boost/tuple/tuple.hpp>

void sample1() {
const int i = boost::get<0>(almost_a_pair);
const std::string& str = boost::get<1>(almost_a_pair);
const double d = boost::get<2>(quad);
}

The boost::get<> function has many overloads and is used widely across Boost. We already saw how it can be used with other libraries in the Storing multiple chosen types in a container/variable recipe.

  1. You can construct tuples using the boost::make_tuple() function, which is shorter to write, because you do not need to fully qualify the tuple type:
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <set>

void sample2() {
// Tuple comparison operators are
// defined in header "boost/tuple/tuple_comparison.hpp"
// Don't forget to include it!
std::set<boost::tuple<int, double, int> > s;
s.insert(boost::make_tuple(1, 1.0, 2));
s.insert(boost::make_tuple(2, 10.0, 2));
s.insert(boost::make_tuple(3, 100.0, 2));

// Requires C++11
const auto t = boost::make_tuple(0, -1.0, 2);
assert(2 == boost::get<2>(t));
// We can make a compile time assert for type
// of t. Interested? See chapter 'Compile time tricks'
}
  1. Another function that makes life easier is boost::tie(). It works almost as make_tuple, but adds a nonconst reference for each of the passed types. Such a tuple can be used to get values to a variable from another tuple. It can be better understood from the following example:
#include <boost/tuple/tuple.hpp>
#include <cassert>

void sample3() {
boost::tuple<int, float, double, int> quad(10, 1.0f, 10.0, 1);
int i;
float f;
double d;
int i2;

// Passing values from 'quad' variables
// to variables 'i', 'f', 'd', 'i2'.
boost::tie(i, f, d, i2) = quad;
assert(i == 10);
assert(i2 == 1);
}

How it works...

Some readers may wonder why we need a tuple when we can always write our own structures with better names; for example, instead of writing boost::tuple<int, std::string>, we can create a structure:

struct id_name_pair { 
int id;
std::string name;
};

Well, this structure is definitely clearer than boost::tuple<int, std::string>. The main idea behind the tuple's library is to simplify template programming.

There's more...

A tuple works as fast as std::pair (it does not allocate memory on a heap and has no virtual functions). The C++ committee found this class to be very useful and it was included in the standard library. You can find it in a C++11 compatible implementation in the header file <tuple> (don't forget to replace all the boost:: namespaces with std::).

The standard library version of tuple must have multiple micro optimizations and typically provides a slightly better user experience. However, there is no guarantee on the order of construction of tuple elements, so, if you need a tuple that constructs its elements starting from the first, you have to use the boost::tuple:

#include <boost/tuple/tuple.hpp>
#include <iostream>

template <int I>
struct printer {
printer() { std::cout << I; }
};

int main() {
// Outputs 012
boost::tuple<printer<0>, printer<1>, printer<2> > t;
}

The current Boost implementation of a tuple does not use variadic templates, does not support rvalue references, does not support C++17 structured bindings, and is not usable with constexpr.

See also

  • Boost's official documentation contains more examples, information about performance, and abilities of Boost.Tuple. It is available at the link http://boost.org/libs/tuple.
  • The Converting all tuple elements to a string recipe in Chapter 8, Metaprogramming, shows some advanced usages of tuples.

Binding and reordering function parameters

If you work with the standard library a lot and use the <algorithm> header, you definitely write a lot of functional objects. In C++14, you can use generic lambdas for that. In C++11, you only have non generic lambdas. In the earlier versions of the C++ standard, you can construct functional objects using adapter functions such as bind1st, bind2nd, ptr_fun, mem_fun, mem_fun_ref, or you can write them by hand (because adapter functions look scary). Here is some good news: Boost.Bind can be used instead of ugly adapter functions, and it provides a more human-readable syntax.

Getting ready

A knowledge of standard library functions and algorithms will be helpful.

How to do it...

Let's see some examples of the usage of Boost.Bind along with C++11 lambda classes:

  1. All the samples require the following headers:

 

// Contains boost::bind and placeholders.
#include <boost/bind.hpp>

// Utility stuff required by samples.
#include <boost/array.hpp>
#include <algorithm>
#include <functional>
#include <string>
#include <cassert>
  1. Count values greater than 5 as shown in the following code:

 

void sample1() {
const boost::array<int, 12> v = {{
1, 2, 3, 4, 5, 6, 7, 100, 99, 98, 97, 96
}};

const std::size_t count0 = std::count_if(v.begin(), v.end(),
[](int x) { return 5 < x; }
);
const std::size_t count1 = std::count_if(v.begin(), v.end(),
boost::bind(std::less<int>(), 5, _1)
);
assert(count0 == count1);
}
  1. This is how we may count empty strings:
void sample2() {
const boost::array<std::string, 3> v = {{
"We ", "are", " the champions!"
}};

const std::size_t count0 = std::count_if(v.begin(), v.end(),
[](const std::string& s) { return s.empty(); }
);
const std::size_t count1 = std::count_if(v.begin(), v.end(),
boost::bind(&std::string::empty, _1)
);
assert(count0 == count1);
}
  1. Now, let's count strings with a length less than 5:
void sample3() {
const boost::array<std::string, 3> v = {{
"We ", "are", " the champions!"
}};

const std::size_t count0 = std::count_if(v.begin(), v.end(),
[](const std::string& s) { return s.size() < 5; }
);
const std::size_t count1 = std::count_if(v.begin(), v.end(),
boost::bind(
std::less<std::size_t>(),
boost::bind(&std::string::size, _1),
5
)
);
assert(count0 == count1);
}
  1. Compare the strings:
void sample4() {
const boost::array<std::string, 3> v = {{
"We ", "are", " the champions!"
}};
std::string s(
"Expensive copy constructor is called when binding"
);

const std::size_t count0 = std::count_if(v.begin(), v.end(),
[&s](const std::string& x) { return x < s; }
);
const std::size_t count1 = std::count_if(v.begin(), v.end(),
boost::bind(std::less<std::string>(), _1, s)
);
assert(count0 == count1);
}

How it works...

The boost::bind function returns a functional object that stores a copy of bound values and a copy of the original functional object. When the actual call to operator() is performed, the stored parameters are passed to the original functional object along with the parameters passed at the time of call.

There's more...

Take a look at the previous examples. When we are binding values, we copy a value into a functional object. For some classes this operation is expensive. Is there a way to bypass copying?

Yes, there is! Boost.Ref library will help us here! It contains two functions, boost::ref() and boost::cref(), the first of which allows us to pass a parameter as a reference, and the second one passes the parameter as a constant reference. The ref() and cref() functions just construct an object of type reference_wrapper<T> or reference_wrapper<const T>, which is implicitly convertible to a reference type. Let's change our last examples:

#include <boost/ref.hpp> 

void sample5() {
const boost::array<std::string, 3> v = {{
"We ", "are", " the champions!"
}};
std::string s(
"Expensive copy constructor is NOT called when binding"
);

const std::size_t count1 = std::count_if(v.begin(), v.end(),
boost::bind(std::less<std::string>(), _1, boost::cref(s))
);
// ...
}

You can also reorder, ignore, and duplicate function parameters using bind:

void sample6() {
const auto twice = boost::bind(std::plus<int>(), _1, _1);
assert(twice(2) == 4);

const auto minus_from_second = boost::bind(std::minus<int>(), _2, _1);
assert(minus_from_second(2, 4) == 2);

const auto sum_second_and_third = boost::bind(
std::plus<int>(), _2, _3
);
assert(sum_second_and_third(10, 20, 30) == 50);
}

The functions ref , cref, and bind are accepted to the C++11 standard and are defined in the <functional> header in the std:: namespace. All these functions do not dynamically allocate memory and do not use virtual functions. The objects returned by them are easy to optimize for a good compiler.

Standard library implementations of those functions may have additional optimizations to reduce compilation time or just compiler-specific optimizations. You may use the standard library versions of bind, ref, cref functions with any Boost library or even mix Boost and standard library versions.

If you are using the C++14 compiler, then use generic lambdas instead of std::bind and boost::bind, as they are less obscure and simpler to understand. C++17 lambdas are usable with constexpr, unlike std::bind and boost::bind.

See also

Getting a human-readable type name

There is often a need to get a readable type name at runtime:

#include <iostream>
#include <typeinfo>

template <class T>
void do_something(const T& x) {
if (x == 0) {
std::cout << "Error: x == 0. T is " << typeid(T).name()
<< std::endl;
}
// ...
}

However, the example from earlier is not very portable. It does not work when RTTI is disabled, and it does not always produce a nice human-readable name. On some platforms, code from earlier will output just i or d.

Things get worse if we need a type name without stripping the const, volatile, and references:

void sample1() {
auto&& x = 42;
std::cout << "x is "
<< typeid(decltype(x)).name()
<< std::endl;
}

Unfortunately, the preceding code outputs int in the best case, which is not what we were expecting.

Getting ready

Basic knowledge of C++ is required for this recipe.

How to do it

In the first case, we need a human-readable type name without qualifiers. The Boost.TypeIndex library will help us out:

#include <iostream>
#include <boost/type_index.hpp>

template <class T>
void do_something_again(const T& x) {
if (x == 0) {
std::cout << "x == 0. T is " << boost::typeindex::type_id<T>()
<< std::endl;
}
// ...
}

In the second case, we need to keep the qualifiers, so we need to call a slightly different function from the same library:

#include <boost/type_index.hpp>

void sample2() {
auto&& x = 42;
std::cout << "x is "
<< boost::typeindex::type_id_with_cvr<decltype(x)>()
<< std::endl;
}

How it works...

The Boost.TypeIndex library has a lot of workarounds for different compilers and knows the most efficient way to produce a human-readable name for the type. If you provide a type as a template parameter, the library guarantees that all the possible type related computations will be performed at compile time and code will work even if RTTI is disabled.

cvr in boost::typeindex::type_id_with_cvr stands for const, volatile, and reference. That makes sure that the type won't be decayed.

There's more...

All the boost::typeindex::type_id* functions return instances of boost::typeindex::type_index. It is very close to std::type_index; however, it additionally, it has a raw_name() method for getting a raw type name, and pretty_name() for getting human-readable type name.

Even in C++17, std::type_index and std::type_info return platform-specific type names representations that are rather hard to decode or use portably.

Unlike the standard library's typeid(), some classes from Boost.TypeIndex are usable with constexpr. It means that you can get a textual representation of your type at compile time if you use a specific boost::typeindex::ctti_type_index class.

Users can invent their own RTTI implementations using the Boost.TypeIndex library. This could be useful for embedded developers and for applications that require extremely efficient RTTI tuned for particular types.

See also

Using the C++11 move emulation

One of the greatest features of the C++11 standard is rvalue references. This feature allows us to modify temporary objects, stealing resources from them. As you can guess, the C++03 standard has no rvalue references, but using the Boost.Move library, you can write a portable code that emulates them.

Getting ready

It is highly recommended that you are at least familiar with the basics of C++11 rvalue references.

How to do it...

  1. Imagine that you have a class with multiple fields, some of which are standard library containers:
namespace other { 
class characteristics{};
}

struct person_info {
std::string name_;
std::string second_name_;
other::characteristics characteristic_;
// ...
};
  1. It is time to add the move assignment and move constructors to it! Just remember that in the C++03 standard library, containers have neither move operators nor move constructors.
  2. The correct implementation of the move assignment is the same move constructing an object and swapping it with this. The correct implementation of the move constructor is close to the default construct and swap. So, let's start with the swap member function:
#include <boost/swap.hpp> 

void person_info::swap(person_info& rhs) {
name_.swap(rhs.name_);
second_name_.swap(rhs.second_name_);
boost::swap(characteristic_, rhs.characteristic_);
}
  1. Now, put the following macro in the private section:
    BOOST_COPYABLE_AND_MOVABLE(person_info) 
  1. Write a copy constructor.
  2. Write a copy assignment, taking the parameter as: BOOST_COPY_ASSIGN_REF(person_info).

 

  1. Write a move constructor and a move assignment, taking the parameter as BOOST_RV_REF(person_info):
struct person_info {
// Fields declared here
// ...
private:
BOOST_COPYABLE_AND_MOVABLE(person_info)
public:
// For the simplicity of example we will assume that
// person_info default constructor and swap are very
// fast/cheap to call.
person_info();

person_info(const person_info& p)
: name_(p.name_)
, second_name_(p.second_name_)
, characteristic_(p.characteristic_)
{}

person_info(BOOST_RV_REF(person_info) person) {
swap(person);
}

person_info& operator=(BOOST_COPY_ASSIGN_REF(person_info) person) {
person_info tmp(person);
swap(tmp);
return *this;
}

person_info& operator=(BOOST_RV_REF(person_info) person) {
person_info tmp(boost::move(person));
swap(tmp);
return *this;
}

void swap(person_info& rhs);
};
  1. Now, we have a portable fast implementation of the move assignment and move construction operators of the person_info class.

How it works...

Here is an example of how the move assignment can be used:

int main() {
person_info vasya;
vasya.name_ = "Vasya";
vasya.second_name_ = "Snow";

person_info new_vasya(boost::move(vasya));
assert(new_vasya.name_ == "Vasya");
assert(new_vasya.second_name_ == "Snow");
assert(vasya.name_.empty());
assert(vasya.second_name_.empty());

vasya = boost::move(new_vasya);
assert(vasya.name_ == "Vasya");
assert(vasya.second_name_ == "Snow");
assert(new_vasya.name_.empty());
assert(new_vasya.second_name_.empty());
}

The Boost.Move library is implemented in a very efficient way. When the C++11 compiler is used, all the macros for rvalues emulation are expanded to C++11-specific features otherwise (on C++03 compilers), rvalues are emulated.

There's more...

Have you noticed the boost::swap call? It is a really helpful utility function, which first searches for a swap function in the namespace of a variable (in our example, it's namespace other::), and if there is no matching swap function, it uses the std::swap.

See also

  • More information about emulation implementation can be found on the Boost website and in the sources of the Boost.Move library at http://boost.org/libs/move.
  • The Boost.Utility library is the one that contains boost::swap, and it has many useful functions and classes. Refer to http://boost.org/libs/utility for its documentation.
  • The Initializing a base class by the member of derived recipe in Chapter 2, Managing Resources.
  • The Making a noncopyable class recipe.
  • In the Making a noncopyable but movable class recipe, there is more info about Boost.Move and some examples on how we can use the movable objects in containers in a portable and efficient way.

Making a noncopyable class

You have almost certainly encountered certain situations, where a class owns some resources that must not be copied for technical reasons:

class descriptor_owner { 
void* descriptor_;

public:
explicit descriptor_owner(const char* params);

~descriptor_owner() {
system_api_free_descriptor(descriptor_);
}
};

The C++ compiler in the preceding example generates a copy constructor and an assignment operator, so the potential user of the descriptor_owner class will be able to create the following awful things:

void i_am_bad() {
descriptor_owner d1("O_o");
descriptor_owner d2("^_^");

// Descriptor of d2 was not correctly freed
d2 = d1;

// destructor of d2 will free the descriptor
// destructor of d1 will try to free already freed descriptor
}

Getting ready

Only very basic knowledge of C++ is required for this recipe.

How to do it...

To avoid such situations, the boost::noncopyable class was invented. If you derive your own class from it, the copy constructor and assignment operator won't be generated by the C++ compiler:

#include <boost/noncopyable.hpp> 

class descriptor_owner_fixed : private boost::noncopyable {
// ...

Now, the user won't be able to do bad things:

void i_am_good() {
descriptor_owner_fixed d1("O_o");
descriptor_owner_fixed d2("^_^");

// Won't compile
d2 = d1;

// Won't compile either
descriptor_owner_fixed d3(d1);
}

How it works...

A refined reader will note that we can achieve exactly the same result by:

  • Making a copy constructor and an assignment operator of descriptor_owning_fixed private
  • Defining them without actual implementation
  • Explicitly deleting them using C++11 syntax = delete;

Yes, you are correct. Depending on the abilities of your compiler, boost::noncopyable class chooses the best way to make the class noncopyable.

boost::noncopyable also serves as a good documentation for your class. It never raises questions such as "Is the copy constructor body defined elsewhere?" or "Does it have a nonstandard copy constructor (with a non-const referenced parameter)?"

See also

  • The Making a noncopyable, but movable class recipe will give you ideas on how to allow unique owning of a resource in C++03 by moving it
  • You may find a lot of helpful functions and classes in the Boost.Core library's official documentation at http://boost.org/libs/core
  • The Initializing a base class by the member of derived recipe in Chapter 2, Managing Resources
  • The Using C++11 move emulation recipe

Making a noncopyable but movable class

Now, imagine the following situation: we have a resource that cannot be copied, which should be correctly freed in a destructor, and we want to return it from a function:

descriptor_owner construct_descriptor() 
{
return descriptor_owner("Construct using this string");
}

Actually, you can work around such situations using the swap method:

void construct_descriptor1(descriptor_owner& ret) 
{
descriptor_owner("Construct using this string").swap(ret);
}

However, such a workaround does not allow us to use descriptor_owner in containers. By the way, it looks awful!

Getting ready

It is highly recommended that you are at least familiar with the basics of C++11 rvalue references. Reading the Using C++11 move emulation recipe is also recommended.

How to do it...

Those readers who use C++11, already know about the move-only classes (like std::unique_ptr or std::thread). Using such an approach, we can make a move-only descriptor_owner class:

class descriptor_owner1 {
void* descriptor_;

public:
descriptor_owner1()
: descriptor_(nullptr)
{}

explicit descriptor_owner1(const char* param);

descriptor_owner1(descriptor_owner1&& param)
: descriptor_(param.descriptor_)
{
param.descriptor_ = nullptr;
}

descriptor_owner1& operator=(descriptor_owner1&& param) {
descriptor_owner1 tmp(std::move(param));
std::swap(descriptor_, tmp.descriptor_);
return *this;
}

void clear() {
free(descriptor_);
descriptor_ = nullptr;
}

bool empty() const {
return !descriptor_;
}

~descriptor_owner1() {
clear();
}
};

// GCC compiles the following in C++11 and later modes.
descriptor_owner1 construct_descriptor2() {
return descriptor_owner1("Construct using this string");
}

void foo_rv() {
std::cout << "C++11n";
descriptor_owner1 desc;
desc = construct_descriptor2();
assert(!desc.empty());
}

This will work only on the C++11 compatible compilers. That is the right moment for Boost.Move! Let's modify our example, so it can be used on C++03 compilers.

According to the documentation, to write a movable but noncopyable type in portable syntax, we need to follow these simple steps:

  1. Put the BOOST_MOVABLE_BUT_NOT_COPYABLE(classname) macro in the private section:
#include <boost/move/move.hpp>

class descriptor_owner_movable {
void* descriptor_;

BOOST_MOVABLE_BUT_NOT_COPYABLE(descriptor_owner_movable
  1. Write a move constructor and a move assignment, taking the parameter as BOOST_RV_REF(classname):
public:
descriptor_owner_movable()
: descriptor_(NULL)
{}

explicit descriptor_owner_movable(const char* param)
: descriptor_(strdup(param))
{}

descriptor_owner_movable(
BOOST_RV_REF(descriptor_owner_movable) param
) BOOST_NOEXCEPT
: descriptor_(param.descriptor_)
{
param.descriptor_ = NULL;
}

descriptor_owner_movable& operator=(
BOOST_RV_REF(descriptor_owner_movable) param) BOOST_NOEXCEPT
{
descriptor_owner_movable tmp(boost::move(param));
std::swap(descriptor_, tmp.descriptor_);
return *this;
}

// ...
};

descriptor_owner_movable construct_descriptor3() {
return descriptor_owner_movable("Construct using this string");
}

How it works...

Now, we have a movable, but non copyable, class that can be used even on C++03 compilers and in Boost.Containers:

#include <boost/container/vector.hpp> 
#include <your_project/descriptor_owner_movable.h>

int main() {
// Following code will work on C++11 and C++03 compilers
descriptor_owner_movable movable;
movable = construct_descriptor3();
boost::container::vector<descriptor_owner_movable> vec;
vec.resize(10);
vec.push_back(construct_descriptor3());

vec.back() = boost::move(vec.front());
}

Unfortunately, C++03 standard library containers still won't be able to use it (that is why we used a vector from Boost.Containers in the previous example).

There's more...

If you want to use Boost.Containers on C++03 compilers, but standard library containers on C++11 compilers, you can do the following simple trick. Add the header file to your project with the following content:

// your_project/vector.hpp 
// Copyright and other stuff goes here

// include guards
#ifndef YOUR_PROJECT_VECTOR_HPP
#define YOUR_PROJECT_VECTOR_HPP

// Contains BOOST_NO_CXX11_RVALUE_REFERENCES macro.
#include <boost/config.hpp>

#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
// We do have rvalues
#include <vector>

namespace your_project_namespace {
using std::vector;
} // your_project_namespace

#else
// We do NOT have rvalues
#include <boost/container/vector.hpp>

namespace your_project_namespace {
using boost::container::vector;
} // your_project_namespace

#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#endif // YOUR_PROJECT_VECTOR_HPP

Now, you can include <your_project/vector.hpp> and use a vector from the namespace your_project_namespace:

int main() {
your_project_namespace::vector<descriptor_owner_movable> v;
v.resize(10);
v.push_back(construct_descriptor3());
v.back() = boost::move(v.front());
}

However, beware of compiler and standard library implementation-specific issues! For example, this code will compile on GCC 4.7 in C++11 mode only if you mark the move constructor, destructor, and move assignment operators with noexcept or BOOST_NOECEPT.

See also

  • The Reducing code size and increasing performance of user-defined type in C++11 recipe in Chapter 10, Gathering Platform and Compiler Information, provides more info on noexcept and BOOST_NOEXCEPT.
  • More information about Boost.Move can be found on Boost's website http://boost.org/libs/move.

Using C++14 and C++11 algorithms

C++11 has a bunch of new cool algorithms in <algorithm> header. C++14 has even more algorithms. If you're stuck with the pre-C++11 compiler, you have to write those from scratch. For example, if you wish to output characters from 65 to 125 code points, you have to write the following code on a pre-C++11 compiler:

#include <boost/array.hpp>

boost::array<unsigned char, 60> chars_65_125_pre11() {
boost::array<unsigned char, 60> res;

const unsigned char offset = 65;
for (std::size_t i = 0; i < res.size(); ++i) {
res[i] = i + offset;
}

return res;
}

Getting ready

Basic knowledge of C++ is required for this recipe along with basic knowledge of Boost.Array library.

How to do it...

The Boost.Algorithm library has all the new C++11 and C++14 algorithms. Using it, you can rewrite the previous example in the following manner:

#include <boost/algorithm/cxx11/iota.hpp>
#include <boost/array.hpp>

boost::array<unsigned char, 60> chars_65_125() {
boost::array<unsigned char, 60> res;
boost::algorithm::iota(res.begin(), res.end(), 65);
return res;
}

How it works...

As you are probably aware, Boost.Algorithm has a header file for each algorithm. Just include the header file and use the required function.

There's more...

It's boring to have a library that just implements algorithms from C++ standard. That's not innovative; that's not the Boost way! That's why you can find in Boost.Algorithm, functions that are not part of C++. Here, for example, is a function that converts input into hexadecimal representation:

#include <boost/algorithm/hex.hpp>
#include <iterator>
#include <iostream>

void to_hex_test1() {
const std::string data = "Hello word";
boost::algorithm::hex(
data.begin(), data.end(),
std::ostream_iterator<char>(std::cout)
);
}

The preceding code outputs the following:

48656C6C6F20776F7264

What's more interesting, all the functions have additional overloads that accept a range as a first parameter instead of two iterators. Range is a concept from Ranges TS. Arrays and containers that have .begin() and .end() functions satisfy the range concept. With that knowledge the previous example could be shortened:

#include <boost/algorithm/hex.hpp>
#include <iterator>
#include <iostream>

void to_hex_test2() {
const std::string data = "Hello word";
boost::algorithm::hex(
data,
std::ostream_iterator<char>(std::cout)
);
}

C++17 will have searching algorithms from Boost.Algorithm. Boost.Algorithm library will be soon extended with new algorithms and C++20 features like constexpr usable algorithms. Keep an eye on that library, as some day, it may get an out-of-the-box solution for a problem that you're dealing with.

See also

Left arrow icon Right arrow icon

Key benefits

  • • Learn to use the Boost libraries to simplify your application development
  • • Learn to develop high quality, fast and portable applications
  • • Learn the relations between Boost and C++11/C++4/C++17

Description

If you want to take advantage of the real power of Boost and C++ and avoid the confusion about which library to use in which situation, then this book is for you. Beginning with the basics of Boost C++, you will move on to learn how the Boost libraries simplify application development. You will learn to convert data such as string to numbers, numbers to string, numbers to numbers and more. Managing resources will become a piece of cake. You’ll see what kind of work can be done at compile time and what Boost containers can do. You will learn everything for the development of high quality fast and portable applications. Write a program once and then you can use it on Linux, Windows, MacOS, Android operating systems. From manipulating images to graphs, directories, timers, files, networking – everyone will find an interesting topic. Be sure that knowledge from this book won’t get outdated, as more and more Boost libraries become part of the C++ Standard.

Who is this book for?

This book is for developers looking to improve their knowledge of Boost and who would like to simplify their application development processes. Prior C++ knowledge and basic knowledge of the standard library is assumed.

What you will learn

  • • Get familiar with new data types for everyday use
  • • Use smart pointers to manage resources
  • • Get to grips with compile-time computations and assertions
  • • Use Boost libraries for multithreading
  • • Learn about parallel execution of different task
  • • Perform common string-related tasks using Boost libraries
  • • Split all the processes, computations, and interactions to tasks and process them independently
  • • Learn the basics of working with graphs, stacktracing, testing and interprocess communications
  • • Explore different helper macros used to detect compiler, platform and Boost features
Estimated delivery fee Deliver to United States

Economy delivery 10 - 13 business days

Free $6.95

Premium delivery 6 - 9 business days

$21.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Aug 30, 2017
Length: 438 pages
Edition : 2nd
Language : English
ISBN-13 : 9781787282247
Vendor :
Microsoft
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to United States

Economy delivery 10 - 13 business days

Free $6.95

Premium delivery 6 - 9 business days

$21.95
(Includes tracking information)

Product Details

Publication date : Aug 30, 2017
Length: 438 pages
Edition : 2nd
Language : English
ISBN-13 : 9781787282247
Vendor :
Microsoft
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 158.97
Mastering the C++17 STL
$48.99
Boost C++ Application Development  Cookbook
$54.99
C++17 STL Cookbook
$54.99
Total $ 158.97 Stars icon
Banner background image

Table of Contents

12 Chapters
Starting to Write Your Application Chevron down icon Chevron up icon
Managing Resources Chevron down icon Chevron up icon
Converting and Casting Chevron down icon Chevron up icon
Compile-Time Tricks Chevron down icon Chevron up icon
Multithreading Chevron down icon Chevron up icon
Manipulating Tasks Chevron down icon Chevron up icon
Manipulating Strings Chevron down icon Chevron up icon
Metaprogramming Chevron down icon Chevron up icon
Containers Chevron down icon Chevron up icon
Gathering Platform and Compiler Information Chevron down icon Chevron up icon
Working with the System Chevron down icon Chevron up icon
Scratching the Tip of the Iceberg Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.2
(5 Ratings)
5 star 80%
4 star 0%
3 star 0%
2 star 0%
1 star 20%
Grigory Nov 03, 2017
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I'm an experienced C++ programmer. One of my friends recommended this book and I enjoyed it.I use Boost for my own projects and know it pretty well. So I read the first few recipes fully and then just started reading Intro+HowToDoIt+TheresMore sections, skipping the detailed recipe description ("How It works").That was great. A lot of good tricks and modern C++ knowledge even for an experienced programmer!I strictly recommend reading this book.
Amazon Verified review Amazon
Jerome Lanteri Aug 30, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
good book for have reference and examples of use for boost C++ lib
Amazon Verified review Amazon
Sergey Platonov Oct 27, 2017
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Liked the easter eggs! Now seriously, the book is well written with a lot of practical advice. It is a set of recipes for everyday use, actually. Every topic (or recipe) consists of five parts: a short introduction of what this topic is about and what you'll need to use it, the recipe itself, explanation, additional information on the subject and related links. I've really enjoyed "There's more..." section. since usually it contains some interesting facts.Strongly recommend this book to every C++ developer, especially, if you just discovered boost or about to use boost ln your project.Of course, some topics seem to be pretty obvious, but I guess one can't know everything, so someone might find this helpful.
Amazon Verified review Amazon
Robert Toby Chaloner Jan 07, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
As a starting point for C++ Boost its very good. Gives a good grounding to build on
Amazon Verified review Amazon
Masum Serazi Feb 06, 2018
Full star icon Empty star icon Empty star icon Empty star icon Empty star icon 1
This book is waste of money. Please don't buy it, rather go to boost official site and read their tutorial.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela