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

5 105 0
HandBooks Professional Java-C-Scrip-SQL part 63 ppsx

Đang tải... (xem toàn văn)

Thông tin tài liệu

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

Ngày đăng: 06/07/2014, 03:20

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan