Tải bản đầy đủ (.pdf) (5 trang)

HandBooks Professional Java-C-Scrip-SQL part 63 ppsx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (20.41 KB, 5 trang )

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));

×