1. Trang chủ
  2. » Công Nghệ Thông Tin

HandBooks Professional Java-C-Scrip-SQL part 67 docx

6 165 0
Tài liệu đã được kiểm tra trùng lặp

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 6
Dung lượng 33,81 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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.. Of course, this

Trang 1

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

Trang 2

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

}

Trang 3

};

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

Trang 4

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

Trang 5

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

Any Summary

Discriminated types can contain values of different types and are quite different from indiscriminate (read void*) types We always depend heavily on type safety

in C++, and there are few situations in which we are willing to do without it

This is for good reasons: Type safety keeps us from making mistakes and improves the performance of our code So, we avoid indiscriminate types Still, it is not uncommon to find oneself in need of heterogeneous storage, or to insulate clients from the details of types, or to gain the utmost flexibility at lower levels of a

hierarchy any provides this functionality while maintaining full type safety, and that makes it an excellent addition to our toolbox!

Use the Any library when

 You need to store values of heterogeneous types in containers

 Storage for unknown types is required

 Types are being passed through layers that need not know anything about the types

The design of Any also serves as a valuable lesson on how to encapsulate a type without effect on the type of the enclosing class This design can be used to create generic function objects, generic iterators, and much more It is an example of the power of encapsulation and polymorphism in conjunction with templates

In the Standard Library, there are excellent tools for storing collections of

elements When the need for storage of heterogeneous types arises, we want to avoid having to use new collection types any offers a solution that works in many cases with existing containers In a way, the template class any extends the

Trang 6

capabilities of the Standard Library containers by packaging disparate types in a homogeneous wrapper that allows them to be made elements of those

aforementioned containers

Adding Boost.Any to an existing code base is straightforward It doesn't require changes to the design, and immediately increases flexibility where it's applied The interface is small, making it a tool that is easily understood

The Any library was created by Kevlin Henney, and like all Boost libraries, has been reviewed, influenced, and refined by the Boost community

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