Initializing a Sequence with Comma-Separated Values

Problem

You want to initialize a sequence with a comma-delimited set of values, like you can with a built-in array.

Solution

You can use a comma-initialization syntax on standard sequences (such as vector and list) by defining a helper class and overloading the comma operator for it as demonstrated in Example 15-6.

Example 15-6. Utilities for comma initialization of standard sequences

#include 
#include 
#include 
#include 

using namespace std; 

template
struct comma_helper
{
 typedef typename Seq_T::value_type value_type;
 explicit comma_helper(Seq_T& x) : m(x) { }
 comma_helper& operator=(const value_type& x) {
 m.clear( );
 return operator+=(x);
 }
 comma_helper& operator+=(const value_type& x) {
 m.push_back(x);
 return *this;
 }
 Seq_T& m;
};

template
comma_helper
initialize(Seq_T& x) {
 return comma_helper(x);
}

template
comma_helper&
operator,(comma_helper& h, Scalar_T x) {
 h += x;
 return h;
}

int main( ) {
 vector v;
 int a = 2;
 int b = 5;
 initialize(v) = 0, 1, 1, a, 3, b, 8, 13;
 cout << v[3] << endl; // outputs 2
 system("pause");
 return EXIT_SUCCESS;
}

 

Discussion

Often time standard sequences are initialized by calling a push_back member function several times. Since this is somewhat repetitive, I wrote a function, initialize, which helps eliminate the tedium, by enabling comma initialization à la built-in arrays.

You may not have been aware that the comma is an operator, let alone an overrideable one. You are not alone; it is not common knowledge. The comma operator was allowed to be overloadable almost precisely for this purpose.

The solution uses a helper function initialize that returns a helper template, comma_helper. The helper template holds a reference to the sequence and overloads operator,, operator=, and operator+=.

This solution required that I define a separate helper function because of the way the compiler reads the statement v = 1, 1, 2, ...;. The compiler treats v = 1 as a subexpression that is not legal because the standard sequences do not support assignment from a single value. What initialize does is construct an appropriate comma_helper object that can hold the sequence while overloading the assignment and comma operator.

The comma operator, also known as the sequencing operator, has a default effect of grouping expressions from left to right and has the same type and value as the righthand value. When overloaded, however, operator, takes on the new meaning and loses the original semantics. This has a subtle effect that the left-to-right evaluation of parameters is no longer guaranteed and code such as in Example 15-7 may not behave as expected.

Example 15-7. Overloaded comma arguments evaluation order undefined

int prompt_user( ) {
 cout << "give me an integer ... ";
 cin >> n;
 return n;
}

void f( ) {
 vector v;
 // The following could result in v being initialized out of
 // sequence
 intialize(v) = prompt_user( ), prompt_user( );
}

The correct way to write f would be to place each call to prompt_user in a separate statement.

The Boost Assign library by Thorsten Ottosen also supports a more complete form of comma list initialization of standard collections, among other forms of initializations. The library is available from http://www.boost.org.


 

Building C++ Applications

Code Organization

Numbers

Strings and Text

Dates and Times

Managing Data with Containers

Algorithms

Classes

Exceptions and Safety

Streams and Files

Science and Mathematics

Multithreading

Internationalization

XML

Miscellaneous

Index



C++ Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2006
Pages: 241

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net