O''''Reilly Network For Information About''''s Book part 72 docx

5 245 0
O''''Reilly Network For Information About''''s Book part 72 docx

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

Thông tin tài liệu

Usage Tuples live in namespace tuples, which in turn is inside namespace boost. Include "boost/tuple/tuple.hpp" to use the library. The relational operators are defined in the header "boost/tuple/tuple_comparison.hpp". Input and output of tuples are defined in "boost/tuple/tuple_io.hpp". A few of the key tuple components (tie and make_tuple) are also available directly in namespace boost. In this section, we'll cover how tuples are used in some typical scenarios, and how it is possible to extend the functionality of the library to best fit our purposes. We'll start with the construction of tuples, and gradually move on to topics that include the details of how tuples can be utilized. Constructing Tuples The construction of a tuple involves declaring the types and, optionally, providing a list of initial values of compatible types. [1] [1] The constructor arguments do not have to be of the exact type specified for the elements when specializing the tuple so long as they are implicitly convertible to those types. boost::tuple<int,double,std::string> triple(42,3.14,"My first tuple!"); The template parameters to the class template tuple specify the element types. The preceding example shows the creation of a tuple with three types: an int, a double, and a std::string. Providing three parameters to the constructor initializes the values of all three elements. It's also possible to pass fewer arguments than there are elements, which results in the remaining elements being default initialized. boost::tuple<short,int,long> another; In this example, another has elements of types short, int, and long, and they are all initialized to 0. [2] Regardless of the set of types for your tuples, this is how they are defined and constructed. So, if one of your tuple's element types is not default constructible, you need to initialize it yourself. Compared to defining structs, tuples are much simpler to declare, define, and use. There's also the convenience function, make_tuple, which makes creating tuples easier still. It deduces the types, relieving you from the monotony (and chance of error!) of specifying them explicitly. [2] Within the context of a template, T() for a built-in type means initialization with zero. boost::tuples::tuple<int,double> get_values() { return boost::make_tuple(6,12.0); } The function make_tuple is analogous to std::make_pair. By default, make_tuple sets the types of the elements to non-const, non-referencethat is, the plain, underlying types of the arguments. For example, consider the following variables: int plain=42; int& ref=plain; const int& cref=ref; These three variables are named after their cv-qualification (constness) and whether they are references. The tuples created by the following invocations of make_tuple all have one int element. boost::make_tuple(plain); boost::make_tuple(ref); boost::make_tuple(cref); This isn't always the right behavior, but on most occasions it is, which is the reason why it's the default. To make an element of a tuple to be of reference type, use the function boost::ref, which is part of another Boost library called Boost.Ref. The following three lines use the variables that we declared earlier, but this time the tuples have an int& element, except for the last, which has a const int& element (we can't remove the constness of cref): boost::make_tuple(boost::ref(plain)); boost::make_tuple(boost::ref(ref)); boost::make_tuple(boost::ref(cref)); If the elements should be const references, use boost::cref from Boost.Ref. Here, the three tuples have one const int& element: boost::make_tuple(boost::cref(plain)); boost::make_tuple(boost::cref(ref)); boost::make_tuple(boost::cref(cref)); It's probably obvious, but ref and cref have plenty of uses in other contexts too. In fact, they were created as a part of the Boost.Tuple library, but were later moved to a separate library because of their general utility. Accessing tuple Elements The elements of a tuple are accessed either through the tuple member function get or the free function get. They both require a constant integral expression designating the index of the element to retrieve. #include <iostream> #include <string> #include "boost/tuple/tuple.hpp" int main() { boost::tuple<int,double,std::string> triple(42,3.14,"The amazing tuple!"); int i=boost::tuples::get<0>(triple); double d=triple.get<1>(); std::string s=boost::get<2>(triple); } In the example, a tuple with three elements with the innovative name triple was created. triple contained an int, a double, and a string, which were retrieved through the get functions. int i=boost::tuples::get<0>(triple); Here, you see the free function get at work. It takes a tuple as its one argument. Note that supplying an invalid index causes an error at compilation time. The precondition is that the index be a valid index for the tuple type. double d=triple.get<1>(); This code shows using the member function get. The preceding line could also have been written like this: double& d=triple.get<1>(); The preceding binding to a reference works because get always returns a reference to the element. If the tuple, or the type, is const, a const reference is returned. The two functions are equivalent, but on some compilers only the free function works correctly. The free function has the advantage of providing a consistent extraction style for types other than tuple. One advantage of accessing the elements of tuples by index rather than by name is that it enables generic solutions, because there are no dependencies on a certain name, but only to an index. More on this later. Tuple Assignment and Copy Construction tuples can be assigned and copy constructed, providing that there are suitable conversions between the types of the elements in the two tuples. To assign or copy tuples, member-wise assignment or copying is performed, so the two tuples must have the same number of elements. The elements in the source tuple must be convertible to those of the destination tuple. The following example shows how this works. #include <iostream> #include <string> #include "boost/tuple/tuple.hpp" class base { public: virtual ~base() {}; virtual void test() { std::cout << "base::test()\n"; } }; class derived : public base { public: virtual void test() { std::cout << "derived::test()\n"; } }; int main() { boost::tuple<int,std::string,derived> tup1(-5,"Tuples"); boost::tuple<unsigned int,std::string,base> tup2; tup2=tup1; tup2.get<2>().test(); std::cout << "Interesting value: " << tup2.get<0>() << '\n'; const boost::tuple<double,std::string,base> tup3(tup2); tup3.get<0>()=3.14; } The example begins by defining two classes, base and derived, which are used as elements of two tuple types. The first tuple contains three elements of types, int, std::string, and derived. The second tuple consists of three elements of the compatible types unsigned int, std::string, and base. Consequently, the two tuples meet the requirements for assignment, which is why tup2=tup1 is valid. In that assignment, the third element of tup1, which is of type derived, is assigned to the third element of tup2, which is of type base. The assignment succeeds, but the derived object is sliced, so this defeats polymorphism. tup2.get<2>().test(); That line extracts a base&, but the object in tup2 is of type base, so it winds up calling base::test. We could have made the behavior truly polymorphic by changing the tuples to contain references or pointers to base and derived, respectively. Note that numeric conversion dangers (loss of precision, positive and negative overflow) apply when converting between tuples as well. These dangerous conversions can be made safe with the help of the Boost.Conversion library, covered in "Library 2: Conversion." The next line in the example copy-constructs a new tuple, tup3, with different, but still compatible types, from tup2. const boost::tuple<double,std::string,base> tup3(tup2); Note that tup3 is declared const. This implies that there is an error in the example. See if you can you spot it. I'll wait…. Did you see it? Here it is: tup3.get<0>()=3.14; Because tup3 is const, get returns a const double&. This means that the assignment statement is ill-formed, and the example doesn't compile. Assignment and copy construction between tuples are intuitive, because the semantics are exactly the same for the tuples as for the individual elements. By way of example, let's see how to give polymorphic behavior to the derived-to-base assignment between tuples. derived d; boost::tuple<int,std::string,derived*> tup4(-5,"Tuples",&d); . statement is ill-formed, and the example doesn't compile. Assignment and copy construction between tuples are intuitive, because the semantics are exactly the same for the tuples as for the individual. which is part of another Boost library called Boost.Ref. The following three lines use the variables that we declared earlier, but this time the tuples have an int& element, except for the. (and chance of error!) of specifying them explicitly. [2] Within the context of a template, T() for a built-in type means initialization with zero. boost::tuples::tuple<int,double> get_values()

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

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

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

Tài liệu liên quan