Usage


The Any library resides in namespace boost. You use the class any to store values, and the template function any_cast to subsequently retrieve the stored values. To use any, include the header "boost/any.hpp". The creation of an instance capable of storing any conceivable value is straightforward.

 boost::any a; 

To assign a value of some type is just as easy.

 a=std::string("A string"); a=42; a=3.1415; 

Almost anything is acceptable to any! However, to actually do anything with the value contained in an any, we need to retrieve it, right? For that, we need to know the value's type.

 std::string s=boost::any_cast<std::string>(a); // throws boost::bad_any_cast. 

This obviously doesn't work; because a currently contains a double, any_cast throws a bad_any_cast exception. The following, however, does work.

 double d=boost::any_cast<double>(a); 

any only allows access to the value if you know the type, which is perfectly sensible. These two elements are all you need to remember, typewise, for this library: the class any, for storing the values, and the template function any_cast, to retrieve them.

Anything Goes!

Consider three classes, A, B, and C, with no common base class, that we'd like to store in a std::vector. If there is no common base class, it would seem we would have to store them as void*, right? Well, not any more (pun intended), because the type of any does not change depending on the type of the value it contains. The following code shows how to solve the problem.

 #include <iostream> #include <string> #include <utility> #include <vector> #include "boost/any.hpp" class A { public:   void some_function() { std::cout << "A::some_function()\n"; } }; class B { public:   void some_function() { std::cout << "B::some_function()\n"; } }; class C { public:   void some_function() { std::cout << "C::some_function()\n"; } }; int main() {   std::cout << "Example of using any.\n\n";   std::vector<boost::any> store_anything;   store_anything.push_back(A());   store_anything.push_back(B());   store_anything.push_back(C());   // While we're at it, let's add a few other things as well   store_anything.push_back(std::string("This is fantastic! "));   store_anything.push_back(3);   store_anything.push_back(std::make_pair(true, 7.92));   void print_any(boost::any& a);   // Defined later; reports on the value in a   std::for_each(     store_anything.begin(),     store_anything.end(),     print_any); } 

Running the example produces the following output.

 Example of using any. A::some_function() B::some_function() C::some_function() string: This is fantastic! Oops! Oops! 

Great, we can store anything we want, but how do we go about retrieving the values that are stored inside the elements of the vector? In the previous example, we used for_each to call print_any() on each element of the vector.

 void print_any(boost::any& a) {   if (A* pA=boost::any_cast<A>(&a)) {     pA->some_function();   }   else if (B* pB=boost::any_cast<B>(&a)) {     pB->some_function();   }   else if (C* pC=boost::any_cast<C>(&a)) {     pC->some_function();   } } 

So far, print_any has tried to retrieve a pointer to an A, B, or C object. This is done with the free function any_cast, which is parameterized on the type to "cast" to. Look closely at the castwe are trying to unlock the any a by saying that we believe that a contains a value with the type A. Also note that we pass our any as a pointer argument to the any_cast function. The return value, therefore, will be a pointer to A, B, or C, respectively. If the any doesn't contain the type that we used in the cast, the null pointer is returned. In the example, if the cast succeeds, we call the some_function member function using the returned pointer. But any_cast can also be used with a slight variation.

   else {     try {       std::cout << boost::any_cast<std::string>(a) << '\n';     }     catch(boost::bad_any_cast&) {       std::cout << "Oops!\n";     }   } } 

Now, this is a bit different. We still perform an any_cast parameterized on the type that we are interested in retrieving, but rather than passing the instance of any as a pointer, it is passed by const reference. This changes the behavior of any_cast; in the case of a failurethat is, asking for the wrong typean exception of type bad_any_cast is thrown. Thus, we have to make sure that we protect the code performing the any_cast with a TRy/catch block if we are not absolutely sure what type of value is contained in the any argument. This behavioral difference (which is analogous with that of dynamic_cast) provides you with a great degree of flexibility. In cases where a cast failure is not an error, pass a pointer to an any, but if a cast failure is an error, pass by const reference, which makes any_cast throw an exception on failure.

Using any enables you to use the Standard Library containers and algorithms in situations not heretofore possible, thus allowing you to write more maintainable and understandable code.

A Property Class

Let's say that we want to define a property class for use in containers. We'll store the names of the properties as strings, and the values can be of any type. Although we could add the requirement that all values be derived from a common base class, that is often not viable. For instance, we may not have access to the source code for all of the classes that we need to use as property values, and some values can be built-in types, which cannot be derived from. (Besides, it wouldn't make for a good any example.) By storing the type of the value in an instance of any, we can leave it to the clients to handle the property values they know about and are interested in.

 #include <iostream> #include <string> #include <vector> #include <algorithm> #include "boost/any.hpp" class property {   boost::any value_;   std::string name_; public:   property(     const std::string& name,     const boost::any& value)   : name_(name),value_(value) {}   std::string name() const { return name_; }   boost::any& value() { return value_; }   friend bool operator<     (const property& lhs, const property& rhs) {     return lhs.name_<rhs.name_;   } }; 

This simple property class has a name stored in a std::string for identification, and an any to hold the value. The flexibility that any brings the implementation is that we are able to use built-in types and user-defined types without changing the property class. Be it simple or complex, an instance of any can always store anything. Of course, using any also means that we cannot know in advance that there is some set of operations that can always be performed on the value stored in a propertywe need to retrieve the value first. This implies that if there is a known set of types that are applicable for use with a property class, we may elect to use a different implementation than any. That's a rare situation when designing frameworksif we don't require a certain base class, all we can safely say is that we have absolutely no idea what classes may be sent our way. When you can get any type and don't need to do anything with it but hold it for a while and give it back, you'll find that any is ideal. Notice that the property class provides operator< to allow the class to be stored in Standard Library associative containers; even without that operator, property would work fine with the sequence containers.

The following program uses our new and flexiblethanks to any!property class. Instances of the property class are stored in a std::map, where the names of the properties are used as the keys.

 void print_names(const property& p) {   std::cout << p.name() << "\n"; } int main() {   std::cout << "Example of using any for storing properties.\n";   std::vector<property> properties;   properties.push_back(     property("B", 30));   properties.push_back(     property("A", std::string("Thirty something")));   properties.push_back(property("C", 3.1415));   std::sort(properties.begin(),properties.end());   std::for_each(     properties.begin(),     properties.end(),     print_names);   std::cout << "\n";   std::cout <<     boost::any_cast<std::string>(properties[0].value()) << "\n";   std::cout <<     boost::any_cast<int>(properties[1].value()) << "\n";   std::cout <<     boost::any_cast<double>(properties[2].value()) << "\n"; } 

Notice that we didn't have to explicitly create the anys needed for property's constructor. That's because any's converting constructor isn't explicit. Although constructors taking one argument should typically be declared explicit, any is an exception to the rule. Running the program gives us this output.

 Example of using any for storing properties. A B C Thirty something 30 3.1415 

In this example, because the container was sorted, we retrieved the properties by index, and as we knew their respective types beforehand, we didn't need a try/catch block for the retrieval. When retrieving the value of an instance of any, pass the any by const reference to any_cast if a failure indicates a real error.

 std::string s=boost::any_cast<std::string>(a); 

When a failure is not necessarily an error, pass the any by pointer.

 std::string* ps=boost::any_cast<std::string>(&a); 

The different styles of getting the stored value differ not only in semantics, but also how they return the stored value. If you pass a pointer argument, you get a pointer to the stored value; if you pass a const reference argument, you get a copy of the value.

If the value type is expensive to copy, pass the any by pointer to avoid copying the value.

There's More to any

There are a few more member functions provided by any, such as testing whether an instance of any is empty or not, and swapping the values of two instances of any. The following example shows how to use them.

 #include <iostream> #include <string> #include "boost/any.hpp" int main() {   std::cout << "Example of using any member functions\n\n";   boost::any a1(100);   boost::any a2(std::string("200"));   boost::any a3;   std::cout << "a3 is ";   if (!a3.empty()) {     std::cout << "not ";   }   std::cout << "empty\n";   a1.swap(a2);   try {     std::string s=boost::any_cast<std::string>(a1);     std::cout << "a1 contains a string: " << s << "\n";   }   catch(boost::bad_any_cast& e) {     std::cout << "I guess a1 doesn't contain a string!\n";   }   if (int* p=boost::any_cast<int>(&a2)) {     std::cout << "a2 seems to have swapped contents with a1: "       << *p << "\n";   }   else {     std::cout << "Nope, no int in a2\n";   }   if (typeid(int)==a2.type()) {     std::cout << "a2's type_info equals the type_info of int\n";   } } 

Here's the output from running the program.

 Example of using any member functions a3 is empty a1 contains a string: 200 a2 seems to have swapped contents with a1: 100 a2's type_info equals the type_info of int 

Let's examine that code more closely. To test whether an instance of any contains a value, we called the member function empty. We tested the any a3 like this.

 std::cout << "a3 is "; if (!a3.empty()) {   std::cout << "not "; } std::cout << "empty\n"; 

Because we default constructed a3, a3.empty() returns TRue. The next thing is to swap the contents of a1 with a2. You may wonder why you'd want to swap their contents. One plausible scenario is when the identities of the any instances are important (swap only exchanges the contained values). Another reason is to avoid copying when you don't need to keep the original value.

 a1.swap(a2); 

Finally, we use the member function type, which returns a const std::type_ info&, to test if the contained value is of the type int.

 if (typeid(int)==a2.type()) { 

Note that if an any stores a pointer type, that is reflected in the returned std::type_info.

Storing Pointers in any

Often, the test for empty is enough to know whether the object really contains something valid. However, if an any might hold a pointer, be extra careful to test the pointer before trying to dereference it. Simply testing whether the any is empty is not enough, because an any is not considered to be empty when it holds a pointer, even if that pointer is null.

 boost::any a(static_cast<std::string*>(0)); if (!a.empty()) {   try {     std::string* p=boost::any_cast<std::string*>(a);     if (p) {           std::cout << *p;     }     else {       std::cout << "The any contained a null pointer!\n";     }   }   catch(boost::bad_any_cast&) {} } 

A Better WayUsing shared_ptr

Another complication when storing raw pointers in any is the destruction semantics. The any class accepts ownership of the value it stores, because it keeps an internal copy of the value, which is destroyed together with the any. However, destroying a raw pointer doesn't invoke delete or delete[] on it! It only reclaims the memory occupied by the pointer. This makes storing a raw pointer in any problematic, so it's a good idea to use smart pointers instead. Indeed, using smart pointers (see "Library 1: Smart_ptr 1") is an ideal way to store a pointer to data in an any. This solves the problem of making sure that the memory associated with a contained pointer is properly deleted. When the smart pointer is destroyed, it takes appropriate action to ensure the memory and any data in it are properly destroyed. By contrast, note that std::auto_ptr is not appropriate. This is because auto_ptr doesn't have normal copy semantics; accessing the value in an any would transfer ownership of the memory and any data in it from the any to the returned auto_ptr.

Consider the following code.

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

First, we'll define two classes, A and B, each with operations is_virtual, which is virtual, and not_virtual, which is not virtual (had it been virtual, the name would be an extremely bad choice). We want to store objects of these types in anys.

 class A { public:   virtual ~A() {     std::cout << "A::~A()\n";   }   void not_virtual() {     std::cout << "A::not_virtual()\n";   }   virtual void is_virtual () {     std::cout << "A:: is_virtual ()\n";   } }; class B : public A { public:   void not_virtual() {     std::cout << "B::not_virtual()\n";   }   virtual void is_virtual () {     std::cout << "B:: is_virtual ()\n";   } }; 

Let's now define a free function, foo, which accepts an argument that is a reference to any and that examines the any using any_casts to the types that the function knows how to handle. If there's no match, the function simply ignores the any and returns. It tests for the types shared_ptr<A> and shared_ptr<B>, respectively, and calls is_virtual (the virtual function) and not_virtual on them.

 void foo(boost::any& a) {   std::cout << "\n";   // Try boost::shared_ptr<A>   try {     boost::shared_ptr<A> ptr=       boost::any_cast<boost::shared_ptr<A> >(a);     std::cout << "This any contained a boost::shared_ptr<A>\n";     ptr-> is_virtual ();     ptr->not_virtual();     return;   }   catch(boost::bad_any_cast& e) {}   // Try boost::shared_ptr<B>   try {     boost::shared_ptr<B> ptr=       boost::any_cast<boost::shared_ptr<B> >(a);     std::cout << "This any contained a boost::shared_ptr<B>\n";     ptr-> is_virtual ();     ptr->not_virtual();     return;   }   catch(boost::bad_any_cast& e) {}   // If anything else (like just a string), ignore it   std::cout <<     "The any didn't contain anything that \      concerns this function!\n"; } 

In main, we create two anys at function scope. We then introduce a new scope, and create two new anys. Next, we store all of the anys in the vector and send every element in it to the function foo, which examines their contents and exercises them. It should be duly noted that we are actually violating the advice that was given earlier, to use the pointer form of any_cast when a failure does not designate an error. However, because we are dealing with smart pointers here, the syntactic advantage of using the exception-throwing form of any_cast is reason enough to ignore the advice this time.

 int main() {   std::cout << "Example of any and shared_ptr\n";   boost::any a1(boost::shared_ptr<A>(new A));   boost::any a2(std::string("Just a string"));   {     boost::any b1(boost::shared_ptr<A>(new B));     boost::any b2(boost::shared_ptr<B>(new B));     std::vector<boost::any> vec;     vec.push_back(a1);     vec.push_back(a2);     vec.push_back(b1);     vec.push_back(b2);     std::for_each(vec.begin(),vec.end(),foo);     std::cout << "\n";   }   std::cout <<     "any's b1 and b2 have been destroyed which means\n"     "that the shared_ptrs' reference counts became zero\n"; } 

When this program is run, it produces the following output.

 Example of any and shared_ptr This any contained a boost::shared_ptr<A> A:: is_virtual () A::not_virtual() The any didn't contain anything that concerns this function! This any contained a boost::shared_ptr<A> B:: is_virtual () A::not_virtual() This any contained a boost::shared_ptr<B> B:: is_virtual () B::not_virtual() A::~A() A::~A() 

First, we see that the any passed to foo contains a shared_ptr<A>, which also happens to own an instance of A. The output is what one would expect.

Next, the any contains the string that we added to our vector. This shows that it is quite possible, and often reasonable, to store types that are unknown to some of the functions that will be called with an any argument; the functions only need to handle the types they are required to operate on!

Then things get really interestingthe third element contains a shared_ptr<A> that is pointing to an instance of B. This is an example of how polymorphism works just the same for any as for other types. Of course, if we were using raw pointers, we could have used static_cast to store the pointer as the type that we want to be the identification tag that unlocks the any. Note that the function A::not_virtual is called instead of B::not_virtual. The reason is that the static type of the pointer is A*, not B*.

The final element contains a shared_ptr<B> that also points to an instance of B. Again, we are controlling the type stored in any, which sets the preferences for those who later try to unlock it.

At the end of the inner scope, the vector is destroyed, which destroys the contained instances of any, which in turn destroys the shared_ptrs, effectively setting the reference counts to zero. Consequently, this means that our pointers are safely and effortlessly destroyed as well!

This example shows something that's more important than how to use smart pointers together with any; it (again) shows that it doesn't really matter how simple or complex the type that we store in any is. If the cost of copying the stored values is prohibitive, or if shared usage and lifetime control is an issue, consider using smart pointers, just as when using the Standard Library containers to store the values. The exact same reasoning applies equally well to using any, and often the two principles coincide, as it is common to use any as a means to store heterogeneous types in containers.

What About Input and Output Operators?

A common question from users of any is "why aren't there input and output operators?" There are indeed good reasons for that. Let's start with the input operator. What would be the semantics for input? Would it default to a string type? Would the current type held by the any be used for extraction from the stream? If so, why would an any be used in the first place? These questions come without good answers, and that's the reason why there's no input operator for any. Answering the second question is not as easy, but almost. Supplying a forwarding output operator for any would mean that any is no longer capable of storing arbitrary types as that operator would impose the same requirement on the types stored by any. It wouldn't even matter if we never intended to use operator<<; an instantiation of an any containing a type that doesn't have an output operator is still illegal, and results in an error when compiling. Of course, were we to provide a template version of operator<<, we would be able to use any without requiring that the contained types support streaming, but as soon as that operator is instantiated, the requirement is on.

There seems to be a cure for missing operators, right? What if we were to supply a valid output operator for any that matches anything, and introduce that operator<< in a scope that is only accessible from the implementation details of the any class? That way, we could elect to throw an exception or return an error code when an output to a stream was performed (the function would only match for arguments without support for operator<<), and we could do this at runtime, without affecting the legality of any other code. This idea struck me as so appealing that I gave it a try on a few of the compilers I have at hand. The results were not good. I won't go into detail, but in short, the solution requires techniques that many compilers can't currently handle. However, we don't necessarily need to change the any classwe could create a new class that takes advantage of any to store arbitrary types, and have that class support operator<<. Basically, we need to do whatever it is any does to keep track of the contained type to know how to write the output, and then add the output streaming.

Adding Support for Outputany_out

We will define a class that is capable of output through operator<<. This adds to the requirements of the types that are to be stored; to be a valid type for storage in the class any_out, the type must support operator<<.

 #include <iostream> #include <vector> #include <string> #include <ostream> #include "boost/any.hpp" class any_out { 

The any_out class stores the (arbitrary) value in a datum of type boost::any. Always select reuse over reinvention!

 boost::any o_; 

Next, we declare an abstract class streamer, which uses the same design as any. We cannot use a parameterized type directly, because we would then need to parameterize any_out as well, which in turns makes the type of any_out dependent on the type of its contained value, effectively rendering the class useless in the context of heterogeneous storage. The type of the contained value must not be a part of the signature for the any_out class.

 struct streamer {   virtual void print(std::ostream& o,boost::any& a)=0;   virtual streamer* clone()=0;   virtual ~streamer() {} }; 

Here's the trick: We add a parameterized class, streamer_imp, parameterized on the contained type and inheriting from streamer. Thus, we are able to store a pointer to streamer in any_out, and rely on polymorphism to do the rest of the work (next, we'll add a virtual member function for that purpose).

 template <typename T> struct streamer_imp : public streamer { 

Now, let's implement a virtual function print to output the value contained in the any by performing an any_cast on the type that streamer_imp is parameterized with. Because we're going to instantiate a streamer_imp on the same type as the value put in the any, the cast doesn't fail.

 virtual void print(std::ostream& o,boost::any& a) {   o << *boost::any_cast<T>(&a); } 

A cloning function is needed when an any_out is being copiedwe are going to store a pointer to streamer, so the virtual function clone takes care of copying the correct type of streamer.

   virtual streamer* clone() {     return new streamer_imp<T>();   } }; class any_out {   streamer* streamer_;   boost::any o_;public: 

The default constructor creates an empty any_out, and sets the streamer pointer to zero.

 any_out() : streamer_(0) {} 

The most interesting function for any_out is the parameterized constructor. The type T, deduced from the type of the value to store, is used when creating the streamer. The value is stored in the any o_.

 template <typename T> any_out(const T& value) :   streamer_(new streamer_imp<T>),o_(value) {} 

Copy construction is straightforward; all we need is to make sure that the streamer in the source any_out a is not zero.

[View full width]

any_out(const any_out& a) : streamer_(a.streamer_?a.streamer_->clone():0),o_(a.o_) {}[1] template<typename T> any_out& operator=(const T& r) { any_out(r).swap(*this); return *this; } any_out& operator=(const any_out& r) { any_out(r).swap(*this); return *this; } ~any_out() { delete streamer_; }

[1] Rob Stewart asked me whether I wrote this line to go for first prize in an obfuscation contest or if I just wanted to be able to write the ():0) emoticon. I'm not really sure, but decided to keep the line for your reading pleasure….

The swap function is supplied to facilitate exception-safe assignment.

 any_out& swap(any_out& r) {   std::swap(streamer_, r.streamer_);   std::swap(o_,r.o_);   return *this; } 

And now, let's add what we came here for: the output operator. It should accept a reference to an ostream and an any_out. The any stored in the any_out should be passed on to the virtual function print of the streamer.

   friend std::ostream& operator<<(std::ostream& o,any_out& a) {     if (a.streamer_) {       a.streamer_->print(o,a.o_);     }     return o;   } }; 

This class not only offers a way to perform stream output of arbitrary (unknown) types contained in a general class, it is also a display of how any is designed. This design, and the techniques used to safely wrap the type behind a polymorphic facade are general, and applicable in more cases than this. For instance, it would be possible to create a generic function adaptor.

Let's take our any_out class for a test drive.

 int main() {   std::vector<any_out> vec;   any_out a(std::string("I do have operator<<"));   vec.push_back(a);   vec.push_back(112);   vec.push_back(65.535);   // Print everything in vector vec   std::cout << vec[0] << "\n";   std::cout << vec[1] << "\n";   std::cout << vec[2] << "\n";   a=std::string("This is great!");   std::cout << a; } 

If the class X does not support operator<<, the code does not compile. Unfortunately, it doesn't matter whether we are actually going to use operator<< or not, it just doesn't work. any_out always requires that the output operator be available.

   any_out nope(X());   std::cout << nope; } 

Convenient, don't you think? If a certain operation is available for all types that you plan to use in a certain context, adding those can be done in the same way we did to supply operator<< for our any_out class. It is not much harder to generalize the solution and parameterize on the operations, which makes this solution for extending the interface of any reusable.

Predicates

Before we end this section on the usage of any, let's examine how to build functionality around any to simplify usage and to add expressive power. When any is used to enable storage of different types in container classes, it turns out that it's easy to store those values but quite hard to operate on them.

First, we will create two predicates, is_int and is_string, which can be used to determine if an any contains an int or a string, respectively. These can be useful when we want to search for a particular type in a container of heterogeneous objects, or want to test the type of an any to determine further actions. The implementation uses the any member function type for the test.

 bool is_int(const boost::any& a) {   return typeid(int)==a.type(); } bool is_string(const boost::any& a) {   return typeid(std::string)==a.type(); } 

The preceding solution works, but it is tedious to write predicates for every type we are interested in testing for. The implementation is repeated, so this would be the perfect fit for a template solution like the following.

 template <typename T> bool contains (const boost::any& a) {   return typeid(T)==a.type(); } 

The function contains saves us from having to manually create new predicates. This is a canonical example of how templates are used to minimize redundant coding.

Counting Non-Empty Values

For certain applications, it is useful to iterate over the elements of a container and test whether the anys contain a value or not. An empty any might imply that it should be removed, or perhaps we need to extract all non-empty elements of any for some further processing. To make this useful in an algorithm, we create a function object with a function call operator taking an any argument. The operator just tests whether the any is empty and, if it is not, increments the counter.

 class any_counter {   int count_; public:   any_counter() : count_(0) {}   int operator()(const boost::any& a) {     return a.empty() ? count_ : ++count_;   }   int count() const { return count_; } }; 

For a container C storing values of any, counting the non-empty values is accomplished like this.

 int i=std::for_each(C.begin(),C.end(),any_counter()).count(); 

Note that the for_each algorithm returns the function object, so we can easily access the count. Because for_each accepts its arguments by value, the following code does not accomplish the same thing.

 any_counter counter; std::for_each(C.begin(),C.end(),counter); int i=counter.count(); 

The second version always yields 0, because the function object counter simply is copied when calling the for_each. The first version works, because the returned function object (the copy of counter) is used for retrieving the count.

Extracting Elements of Certain Types from a Container

Here's an extra treat: An extractor for retrieving certain types from a container. This can be a useful utility when parts of a heterogeneous container are to be transferred to a homogeneous container. Manually, this is a tedious and error-prone task, but one simple function object takes care of everything for us. We will parameterize the function object on the type of output iterator for the retrieved elements, and the type to extract from the any arguments that are passed to it.

 template <typename OutIt,typename Type> class extractor {   OutIt it_; public:   extractor(OutIt it) : it_(it) {}   void operator()(boost::any& a) {     Type* t(boost::any_cast<Type>(&a));     if (t) {       *it_++ = *t;     }   } }; 

As a convenience for creating an extractor, here's a function that deduces the type of the output iterator and returns an appropriate extractor.

 template <typename Type, typename OutIt>   extractor<OutIt,Type>   make_extractor(OutIt it) {     return extractor<OutIt,Type>(it);   } 

Using the Predicates and the Extractor

It's high time to test our new any companions with a sample program.

 int main() {    std::cout << "Example of using predicates and the "     "function object any_counter\n";   std::vector<boost::any> vec;   vec.push_back(boost::any());   for(int i=0;i<10;++i) {     vec.push_back(i);   }   vec.push_back(boost::any()); 

We have added 12 any objects to the vec, and now we're interested in finding out how many of the elements contain a value. To count elements with values, we use the function object any_counter that we've created.

 // Count the instances of any that contain a value int i=std::for_each(   vec.begin(),   vec.end(),   any_counter()).count(); std::cout   << "There are " << i << " non-empty any's in vec\n\n"; 

Here is how the extractor function object that operates on a container of anys works, populating a new container with a certain type collected from the source container.

   // Get all ints in vec std::list<int> lst; std::for_each(vec.begin(),vec.end(),   make_extractor<int>(std::back_inserter(lst))); std::cout << "Found " << lst.size() << " ints in vec\n\n"; 

Let's clear the contents of the container vec and add some new values.

 vec.clear(); vec.push_back(std::string("This is a string")); vec.push_back(42); vec.push_back(3.14); 

Now, let's try the predicates that we created. First, we use the two predicates that indicate whether an any contains a string or an int, respectively.

 if (is_string(vec[0])) {   std::cout << "Found me a string!\n"; } if (is_int(vec[1])) {   std::cout << "Found me an int!\n"; } 

As we concluded earlier, defining predicates for every type we are ever interested in is tedious and utterly unnecessary, when we can use the language to our advantage in a straightforward manner.

   if (contains<double>(vec[2])) {     std::cout <<       "The generic tool is sweeter, found me a double!\n";   } } 

Running this example gives you this output.

 Example of using predicates and the function object any_counter There are 10 non-empty any's in vec Found 10 ints in vec Found me a string! Found me an int! The generic tool is sweeter, found me a double! 

Small and simple tools like these have proven to be very useful. Of course, this is not only true for any; it's a property of the design of the Standard Library containers and algorithms. The examples show how to take advantage of function composition together with any. Providing filtering, counting, operations on certain types, and so forth are powerful ways of hiding implementation details, and simplifying the usage of any.

Complying with the Requirements of Standard Library Adapters

If you found the predicate contains useful, you may have noticed that it is not quite all it can be. There is no way to use it together with the Standard Library adapters. The following example is slightly outside the scope of this chapter, but because any fits so well with the container classes, it would be a shame to leave a somewhat flawed predicate of contains as is. The problem is that the Standard Library adapters (bind1st, bind2nd, not1, and not2) impose requirements on the predicates they adapt. The type of the argument and the result type must be exposed through provided typedefs, and that means that we need a function object rather than a function.

First comes the definition of our new function object, contains_t. It could have inherited from the helper class std::unary_function (part of the C++ Standard Library, intended to facilitate the creation of the correct typedefs) and have the argument and result types defined automatically, but to make things clear, the required typedefs are provided explicitly. The argument type has changed from const boost::any& to boost::any, to avoid a potential reference-to-reference, which is illegal. The implementation is just as before, only here it is placed in the function call operator.

 template <typename T> struct contains_t {   typedef boost::any argument_type;   typedef bool result_type;   bool operator()(boost::any a) const {     return typeid(T)==a.type();   } }; 

To save the name contains for subsequent use in the helper function that's soon to come, the name of the function object is contains_t. Here is a helper function that creates and returns an instance of contains_t with the appropriate type set automatically. The reason is that we want to overload contains so that we are still able to provide the original predicate that we created.

 template <typename T> contains_t<T> contains() {   return contains_t<T>(); } 

Finally, the good old predicate is changed to take advantage of the contains_t implementation. Now, if we need to change the implementation of contains_t for some reason, contains will reflect those changes without any further effort.

 template <typename T> bool contains(const boost::any& a) {   return contains_t<T>()(a); } 

Here's a sample program that demonstrates what we have gained, using both the new function object and the predicate from the previous example.

 int main() {   std::cout << "Example of using the improved is_type\n";   std::vector<boost::any> vec;   vec.push_back(std::string("This is a string"));   vec.push_back(42);   vec.push_back(3.14); 

Using the predicate is no different than before. Testing an any for a certain type is still easy.

 if (contains<double>(vec[2])) {   std::cout << "The generic tool has become sweeter! \n"; } vec.push_back(2.52f); vec.push_back(std::string("Another string")); 

Another example of the use of contains is to search a container for occurrences of a certain type. This example finds the first float.

 std::vector<boost::any>::iterator   it=std::find_if(vec.begin(),vec.end(),contains<float>()); 

As yet another reminder, the two ways of retrieving the contained value of an any are demonstrated. Pass the any to any_cast by const reference for the exception-throwing version. Pass the address of the any to return a pointer to the stored value.

 if (it!=vec.end()) {   std::cout << "\nPrint the float twice!\n";   std::cout << boost::any_cast<float>(*it) << "\n";   std::cout << *boost::any_cast<float>(&*it) << "\n"; } std::cout <<   "There are " << vec.size() << " elements in vec\n"; 

I still haven't given a good example of why contains should be a full-fledged function object. In many cases, the reasons why may not be known beforehand, because we cannot anticipate every situation that our implementations will face. That's a strong reason to comply with the requirements of the Standard Library facilities, preferably in more than just the use cases that we are currently aware of. Nevertheless, I do have an example for you: The task is to remove all elements from a container vec that do not contain strings. Of course, writing another predicate that does the exact opposite of contains is one alternative, but that's an alternative that quickly can lead to maintenance nightmares, because of proliferation of function objects with similar work descriptions. The Standard Library provides us with an adapter called not1, which negates the result of an invocation of a function object, and this makes it trivial to clean out all non-string elements from our vector vec.

   vec.erase(std::remove_if(vec.begin(),vec.end(),   std::not1(contains<std::string>())),vec.end());   std::cout << "Now, there are only " << vec.size()     << " elements left in vec!\n"; } 

The examples in this section have demonstrated how to make effective use of any. Because the type of the stored value is not part of any's type, any is an essential tool when providing storage without imposing requirements on the stored types, including inheriting from a certain base class. We have seen that there is a price for this type hiding. any disallows access to the stored value without knowledge of the value's type, restricting opportunities to operate on the stored values. To a large extent, this can be amended by creating helper classespredicates and function objectsthat provide the necessary logic to access the values.



    Beyond the C++ Standard Library(c) An Introduction to Boost
    Beyond the C++ Standard Library: An Introduction to Boost
    ISBN: 0321133544
    EAN: 2147483647
    Year: 2006
    Pages: 125

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