(ebook) boost c++ application development cookbook - second edition: recipes to simplify your applic
(Ebook) Boost C++ Application Development Cookbook - Second Edition: Recipes to simplify your application development by Antony Polukhin ISBN 9781787282247, 1787282244 download
(Ebook) Modern C++: Efficient and Scalable Application Development: Leverage the modern features of C++ to overcome difficulties in various stages of application development by Richard Grimes; Marius Bancila ISBN 9781789951738, 1789951739
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
First published: August 2013
Production Reference: 1210813
Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.
ISBN 978-1-84951-488-0 www.packtpub.com
Cover Image by Suresh Mogre (suresh.mogre.99@gmail.com)
Credits
Author
Antony Polukhin
Reviewers
Béla Tibor Bartha
Paul A. Bristow
Acquisition Editor
Akram Hussain
Lead Technical Editor
Arun Nadar
Technical Editors
Sampreshita Maheshwari
Vivek Pillai
Hardik B. Soni
Copy Editors
Adithi Shetty
Laxmi Subramanian
Gladson Monterio
Brandt D'Mello
Sayanee Mukherjee
Alfida Paiva
Aditya Nair
Project Coordinator
Anugya Khurana
Proofreader
Stephen Silk
Indexer
Monica Ajmera Mehta
Graphics
Abhinash Sahu
Ronak Druv
Production Coordinator
Conidon Miranda
Cover Work
Conidon Miranda
About the Author
Antony Polukhin was born in Russia. As a child, he could speak the Russian and Hungarian languages and learned English at school. Since his school days, he was participating in different mathematics, physics, and chemistry competitions and winning them.
He was accepted into University twice: once for taking part in a city mathematics competition and again for gaining high score in an internal Universities mathematics and physics challenge. In his university life, there was not a year when he did not participate in an exam: he gained 'A's in all disciplines by writing highly difficult programs for each teacher. He met his future wife in university and graduated with honors.
For more than three years, he worked in a VoIP company developing business logic for a commercial alternative to Asterisc. During those days he started contributing to Boost and became a maintainer of the Boost.LexicalCast library. He also started making translations to Russian for Ubuntu Linux at that time.
Today, he develops a query engine for graph-oriented databases and continues to contribute to the open source. You may find his code in Boost libraries such as Any, LexicalCast, TypeTraits, Variant, and others.
He has been happily married for a year now.
I would like to thank my family, especially my wife, Irina Polukhina, for drawing sketches of pictures and diagrams all through the book. Great thanks to Paul Anthony Bristow for reviewing this book and getting through the insane number of commas that I used in the first drafts. I would also like to thank all of the people from the Boost community for writing those great libraries and for opening an amazing word of C++ for me.
About the Reviewers
Béla Tibor Bartha is a professional software engineer working on various technologies and languages. Although in the last four years he's been working on iOS and OS X applications, C++ is his old passion along with game development as personal projects.
Paul A. Bristow is a long-time member of the Boost community (and contributor to Boost. Math) who has watched with amusement and amazement at how C++ has been made to do so many wonderful things that it was never designed to do (many of which are nicely demonstrated in this book).
www.PacktPub.com
Support files, eBooks, discount offers and more
You might want to visit www.PacktPub.com for support files and downloads related to your book.
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at service@packtpub.com for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks.
TM http://PacktLib.PacktPub.com
Do you need instant solutions to your IT questions? PacktLib is Packt's online digital book library. Here, you can access, read and search across Packt's entire library of books.
Why Subscribe?
f Fully searchable across every book published by Packt
f Copy and paste, print and bookmark content
f On demand and accessible via web browser
Free Access for Packt account holders
If you have an account with Packt at www.PacktPub.com, you can use this to access PacktLib today and view nine entirely free books. Simply use your login credentials for immediate access.
Preface
A few years ago one of my friends was looking for a book about the Boost libraries. I asked him "Why don't you read the documentation?". His answer was, "I do not know much and I do not know where to start. Boost is huge; I have no time to read all about it."
Well, that was a good hint but such a book would be of interest only to beginners. Professionals would find nothing interesting in it unless I added some C++11 stuff and compared the existing Boost libraries with the new C++ standard.
I could also add answers to common questions that arise in Boost mailing lists but are hard to find or not covered by the documentation. Spice it up with performance notes and we'd get a book that would be interesting to almost everyone.
This book will take you through a number of clear, practical recipes that will help you to take advantage of some readily available solutions.
Boost C++ Application Development Cookbook starts out teaching the basics of the Boost libraries that are now mostly part of C++11 and leave no chance for memory leaks. Managing resources will become a piece of cake. We'll see what kind of work can be done at compile time and what Boost containers can do. Do you think multithreading is a burden? Not with Boost. Do you think writing portable and fast servers is impossible? You'll be surprised! Compilers and operating systems differ too much? Not with Boost. From manipulating images to graphs, directories, timers, files, and strings – everyone will find an interesting topic.
You will learn everything needed for the development of high-quality, fast, and portable applications. Write a program once and you can use it on Linux, Windows, Mac OS, and Android operating systems.
What this book covers
Chapter 1, Starting to Write Your Application, covers 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 datatypes introduced by Boost library authors.
Chapter 2, Converting Data, explains how to convert strings, numbers, and user-defined types to each other, how to safely cast polymorphic types, and how to write small and large parsers right in C++ source files.
Chapter 3, Managing Resources, provides guidance to easily managing resources and how to use a datatype capable of storing any functional objects, functions, and lambda expressions. After reading this chapter your code will become more reliable and memory leaks will become history.
Chapter 4, Compile-time Tricks, walks you through some basic examples on how Boost libraries can be used in compile-time checking, for tuning algorithms and in other metaprogramming tasks.
Chapter 5, Multithreading, discusses threads and everything connected with them.
Chapter 6, Manipulating Tasks, explains that we can split all of the processing, computations, and interactions to functors (tasks) and process each of those tasks almost independently. Moreover, we need not block on some slow operations such as receiving data from socket or waiting for timeout, but instead provide a callback task and continue processing other tasks.
Chapter 7, Manipulating Strings, covers different aspects of changing, searching, and representing strings. We'll see how some common string-related tasks can easily be done using Boost libraries.
Chapter 8, Metaprogramming, is devoted to some cool and hard-to-understand metaprogramming methods. Those methods are not for everyday use, but they will be a real help for development of generic libraries.
Chapter 9, Containers, covers Boost containers and everything directly connected to them. This chapter provides information about Boost classes that can be used in everyday programming and that will make your code much faster and development of new applications easier.
Chapter 10, Gathering Platform and Compiler Information, provides different helper macros used to detect compiler, platform, and Boost features. Those macros are widely used across Boost libraries and are essential for writing portable code that is able to work with any compiler flags.
Chapter 11, Working with the System, takes a closer look at the filesystem and at creating and deleting files. We'll see how data can be passed between different system processes, how to read files with maximum speed, and how to do other tricks.
Chapter 12, Scratching the Tip of the Iceberg, is devoted to some of those big libraries, giving the basics to start with. Some of the Boost libraries are small and meant for everyday use, others require a separate book to describe all of their features.
What you need for this book
To run the examples in this book, the following software will be required:
f C++ compiler: Any modern, popular C++ compiler will be suitable
f IDE: QtCreator is recommended as an IDE
f Boost: You should have a full build of Boost 1.53
f Miscellaneous tools: Graphviz (any version) and libpng (latest version)
Note that if you are using Linux, all of the required software except Boost can be found in the repository.
Who this book is for
This book is great for developers who are new to Boost, and who are looking to improve their knowledge of Boost and see some undocumented details or tricks. It's assumed that you will have some experience in C++ already, as well as being familiar with the basics of STL. A few chapters will require some previous knowledge of multithreading and networking. You are expected to have at least one good C++ compiler and compiled version of Boost (1.53.0 or later is recommended), which will be used during the exercises within this book.
Conventions
In this book, you will find a number of styles of text that distinguish between different kinds of information. Here are some examples of these styles, and an explanation of their meaning.
Code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles are shown as follows: "It means that you can catch almost all Boost exceptions using catch (const std::exception& e)."
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; return 0; }
New terms and important words are shown in bold.
Warnings or important notes appear in a box like this.
Tips and tricks appear like this.
Reader feedback
Feedback from our readers is always welcome. Let us know what you think about this book—what you liked or may have disliked. Reader feedback is important for us to develop titles that you really get the most out of.
To send us general feedback, simply send an e-mail to feedback@packtpub.com, and mention the book title via the subject of your message.
If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, see our author guide on www.packtpub.com/authors
Customer support
Now that you are the proud owner of a Packt book, we have a number of things to help you to get the most from your purchase.
Downloading the example code
You can download the example code files for all Packt books 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 e-mailed directly to you.
Preface 4
Errata
Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you find a mistake in one of our books—maybe a mistake in the text or the code— we would be grateful if you would report this to us. By doing so, you can save other readers from frustration and help us improve subsequent versions of this book. If you find any errata, please report them by visiting http://www.packtpub.com/submit-errata, selecting your book, clicking on the errata submission form link, and entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata will be uploaded on our website, or added to any list of existing errata, under the Errata section of that title. Any existing errata can be viewed by selecting your title from http://www. packtpub.com/support.
Piracy
Piracy of copyright material on the Internet is an ongoing problem across all media. At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works, in any form, on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy.
Please contact us at copyright@packtpub.com with a link to the suspected pirated material.
We appreciate your help in protecting our authors, and our ability to bring you valuable content.
Questions
You can contact us at questions@packtpub.com if you are having a problem with any aspect of the book, and we will do our best to address it.
In this chapter we will cover:
1 Starting to Write Your Application
f Getting configuration options
f Storing any value in a container/variable
f Storing multiple chosen types in a container/variable
f Using a safer way to work with a container that stores multiple chosen types
f Returning a value or flag where there is no value
f Returning an array from a function
f Combining multiple values into one
f Reordering the parameters of a function
f Binding a value as a function parameter
f Using the C++11 move emulation
f Making a noncopyable class
f Making a noncopyable but movable class
Introduction
Boost is a collection of C++ libraries. Each library has been reviewed by many professional programmers before being accepted to Boost. Libraries are tested on multiple platforms using many compilers and the 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.
Starting to Write Your Application
Many parts of Boost have been included in C++11, and even more parts are going to be included in the next standard of C++. You will find C++11-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 datatypes 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. And 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 a header-only, so your program will need to link against the libboost_program_ options library.
How to do it...
Let's start with a simple program that accepts the number of apples and oranges as input and counts the total number of fruits. We want to achieve the following result:
$ our_program –apples=10 –oranges=20
Fruits count: 30
Perform the following steps:
1. First of all, we need to include the program_options 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;
2. Now we are ready to describe our options:
// Constructing an options describing variable and giving // it a textual description "All options" to it. 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") ;
3. We'll see how to use a third parameter a little bit later, after which we'll deal with parsing the command line and outputting the result:
// Variable to store our command line arguments opt::variables_map vm;
4. Let's add the --help parameter to our option's description: ("help", "produce help message")
5. Now add the following lines after opt::notify(vm);, and you'll get a fully functional help for your program: if (vm.count("help")) { std::cout << desc << "\n"; return 1; }
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 option's value, because we do not expect any values to be passed to it.
6. Once we have got through all the basics, let's add short names for some of the options, set the default value for apples, add some string input, and get the missing options from the configuration file:
#include <boost/program_options.hpp> // 'reading_file' exception class is declared in errors.hpp #include <boost/program_options/errors.hpp> #include <iostream> namespace opt = boost::program_options; int main(int argc, char *argv[]) {
opt::options_description desc("All options"); // 'a' and 'o' are short option names for apples and // oranges 'name' option is not marked with // 'required()', so user may not support it desc.add_options() ("apples,a", opt::value<int>()->default_value(10), "apples that you have") ("oranges,o", opt::value<int>(), "oranges that you have") ("name", opt::value<std::string>(), "your name") ("help", "produce help message") ; opt::variables_map vm; // Parsing command line options and storing values to 'vm'
// We can also parse environment variables using // 'parse_environment' method
opt::notify(vm);
if (vm.count("help")) {
std::cout << desc << "\n"; return 1; }
// Adding missing options from "aples_oranges.cfg" // config file.
// You can also provide an istreamable object as a // first parameter for 'parse_config_file' // 'char' template parameter will be passed to // underlying std::basic_istream object
try { opt::store( opt::parse_config_file<char>("apples_oranges.cfg", desc), vm );
} catch (const opt::reading_file& e) { std::cout << "Failed to open file 'apples_oranges.cfg': " << e.what(); } opt::notify(vm); if (vm.count("name")) {
When using a configuration file, we need to remember that its syntax differs from the command-line syntax. We do not need to place minuses before the options. So our apples_oranges.cfg option must look like this: oranges=20
Starting to Write Your Application
How it works...
This example is pretty trivial to understand from code and comments. Much more interesting is what output we get on execution:
$ ./our_program --help
All options: -a [ --apples ] arg (=10) how many apples do you have -o [ --oranges ] arg how many oranges do you have --name arg your name --help produce help message
$ ./our_program
Fruits count: 30
$ ./our_program -a 10 -o 10 --name="Reader"
Hi,Reader!
Fruits count: 20
There's more...
The C++11 standard adopted many Boost libraries; however, you won't find Boost. ProgramOptions in it.
See also
f Boost's official documentation contains many more examples and shows more advanced features of Boost.ProgramOptions, such as position-dependent options, nonconventional syntax, and more. This is available at the following link: http://www.boost.org/doc/libs/1_53_0/doc/html/program_options. html
Downloading the example code
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 e-mailed directly to you.
Storing any value in a container/variable
If you have been programming in Java, C#, or Delphi, you will definitely miss the ability to create 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++:
(*p) += " That is great!\n"; std::cout << *p; return 0; }
Getting ready
We'll be working with the header-only library. Basic knowledge of C++ is all you need for this recipe.
How to do it...
In such cases, Boost offers a solution, the Boost.Any library, which has an even better syntax:
#include <boost/any.hpp>
#include <iostream>
#include <vector>
#include <string>
Starting to Write Your Application
int main()
{
std::vector<boost::any> some_values; some_values.push_back(10); const char* c_str = "Hello there!"; some_values.push_back(c_str); some_values.push_back(std::string("Wow!")); std::string& s = boost::any_cast<std::string&>(some_values.back()); s += " That is great!\n"; std::cout << s; return 0; }
Great, isn't it? By the way, it has an empty state, which could be checked using the empty() member function (just as in STL containers).
You can get the value from boost::any using two approaches: boost::any variable(std::string("Hello world!"));
//#1: 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);
//#2: 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 of its types). To use this library, you do not really need to know its internal implementation, so let's just have a quick glance at the type erasure technique. Boost.Any, on assignment of some variable of type T, constructs a type (let's call it holder<T>) that may store a value of the specified type T, and is derived from some internal base-type placeholder. A placeholder has virtual functions for getting std::type_info of a stored type and for cloning a stored type. When any_cast<T>() is used, boost::any checks that std::type_info of a stored value is equal to typeid(T) (the overloaded placeholder's function is used for getting std::type_info).
There's more...
Such flexibility never comes without a cost. Copy constructing, value constructing, copy assigning, and assigning values to instances of boost::any will call a dynamic memory allocation function; all of the type casts need to get runtime type information (RTTI); boost::any uses virtual functions a lot. If you are keen on performance, see the next recipe, which will give you an idea of how to achieve almost the same results without dynamic allocations and RTTI usage.
Another disadvantage of Boost.Any is that it cannot be used with RTTI disabled. There is a possibility to make this library usable even with RTTI disabled, but it is not currently implemented.
Almost all exceptions in Boost derive 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
f Boost's official documentation may give you some more examples, and it can be found at http://www.boost.org/doc/libs/1_53_0/doc/html/any.html
f The Using a safer way to work with a container that stores multiple chosen types recipe for more info on the topic
Starting
to Write Your Application
Storing multiple chosen types in a variable/ container
Are you aware of the concept of unrestricted unions in C++11? Let me tell you about it in short. C++03 unions can only hold extremely simple types of data called POD (plain old data). So in C++03, you cannot, for example, store std::string or std::vector in a union. C++11 relaxes this requirement, but you'll have to manage the construction and destruction of such types by yourself, call in-place construction/destruction, and remember what type is stored in a union. A huge amount of work, isn't it?
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 doesn't 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; return 0; }
Great, isn't it?
2. Boost.Variant has no empty state, but has an empty() function, which always returns false. If you do need to represent an empty state, just add some trivial 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: typedef boost::variant<boost::blank, int, const char*, std::string> my_var_t; // Default constructor will construct an // instance of boost::blank my_var_t var; // 'which()' method returns an index of a type, // currently held by variant. assert(var.which() == 0); // Empty state var = "Hello, dear reader"; assert(var.which() != 0);
3. You can get a value from a variant using two approaches: 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 an NULL pointer int* s2 = boost::get<int>(&variable);
How it works...
The boost::variant class holds an array of characters and stores values in that array. Size of the array is determined at compile time using sizeof() and functions to get alignment. On assignment or construction of boost::variant, the previous values are in-place destroyed, and new values are constructed on top of the character array using the new placement.
There's more...
The Boost.Variant variables usually do not allocate memory in a heap, 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 trivial type in the list of supported types, and that this type is at the first position.
Boost.Variant is not a part of the C++11 standard.
Starting to Write Your Application
See also
f The Using a safer way to work with a container that stores multiple chosen types recipe
f Boost's official documentation contains more examples and descriptions of some other features of Boost.Variant, and can be found at: http://www.boost.org/doc/libs/1_53_0/doc/html/variant.html
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 be using your classes, and his task would be to get a row from the database and count the sum of the arithmetic types in a row.
Here's how the code would look:
#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 Using a // reference to string type in Chapter 7, Manipulating Strings // for an answer.
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; return 0; }
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 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 to the mind of a programmer who will use your interface. So you'll need to carefully document values stored by your cell_t, or read the more elegant solution 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.
Starting
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 variant type, 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. 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 the recipe "Using a reference to string type" // in Chapter 7, Manipulating Strings // 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 how 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; }