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
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Boost C++ Application Development  Cookbook

You're reading from   Boost C++ Application Development Cookbook Recipes to simplify your application development

Arrow left icon
Product type Paperback
Published in Aug 2017
Publisher Packt
ISBN-13 9781787282247
Length 438 pages
Edition 2nd Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Anton Polukhin Alekseevic Anton Polukhin Alekseevic
Author Profile Icon Anton Polukhin Alekseevic
Anton Polukhin Alekseevic
Arrow right icon
View More author details
Toc

Table of Contents (13) Chapters Close

Preface 1. Starting to Write Your Application FREE CHAPTER 2. Managing Resources 3. Converting and Casting 4. Compile-Time Tricks 5. Multithreading 6. Manipulating Tasks 7. Manipulating Strings 8. Metaprogramming 9. Containers 10. Gathering Platform and Compiler Information 11. Working with the System 12. Scratching the Tip of the Iceberg

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

You have been reading a chapter from
Boost C++ Application Development Cookbook - Second Edition
Published in: Aug 2017
Publisher: Packt
ISBN-13: 9781787282247
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image