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

HandBooks Professional Java-C-Scrip-SQL part 74 ppt

6 54 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 22,38 KB

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

Nội dung

For example, you can get the length of a tuple the number of elements, retrieve the type of an element, and use the null_type tuple sentinel to terminate recursive template instantiation

Trang 1

int main() {

boost::tuple<int,double> tup1;

boost::tuple<long,long,long> tup2;

std::cout << "Enter an int and a double as (1 2.3):\n";

std::cin >> tup1;

std::cout << "Enter three ints as |1.2.3|:\n";

std::cin >> boost::tuples::set_open('|') >>

boost::tuples::set_close('|') >>

boost::tuples::set_delimiter('.') >> tup2;

std::cout << "Here they are:\n"

<< tup1 << '\n'

<< boost::tuples::set_open('\"') <<

boost::tuples::set_close('\"') <<

boost::tuples::set_delimiter('-');

std::cout << tup2 << '\n';

}

The previous example shows how to use the streaming operators together with tuples The default delimiters for tuples are ( (left parenthesis) as opening delimiter, ) (right parenthesis) for the closing delimiter, and a space for delimiting tuple element values This implies that to get our program working correctly, we need to give the program input like(12 54.1) and |4.5.3| Here's a sample run

Enter an int and a double as (1 2.3):

(12 54.1)

Enter three ints as |1.2.3|:

|4.5.3|

Here they are:

(12 54.1)

"4-5-3"

The support for streaming is convenient and, with the support of the delimiter manipulators, it's easy to make streaming compatible even with legacy code that has been updated to use tuples

Finding Out More About Tuples

There are more facilities for tuples than those we've already seen These more advanced features are vital for creating generic constructs that work with tuples

Trang 2

For example, you can get the length of a tuple (the number of elements), retrieve the type of an element, and use the null_type tuple sentinel to terminate recursive template instantiations

It's not possible to iterate over the elements of a tuple with a for loop, because get requires a constant integral expression However, using a template

metaprogram, we can print all the elements of a tuple

#include <iostream>

#include <string>

#include "boost/tuple/tuple.hpp"

template <typename Tuple,int Index> struct print_helper {

static void print(const Tuple& t) {

std::cout << boost::tuples::get<Index>(t) << '\n';

print_helper<Tuple,Index-1>::print(t);

}

};

template<typename Tuple> struct print_helper<Tuple,0> {

static void print(const Tuple& t) {

std::cout << boost::tuples::get<0>(t) << '\n';

}

};

template <typename Tuple> void print_all(const Tuple& t) {

print_helper<

Tuple,boost::tuples::length<Tuple>::value-1>::print(t);

}

int main() {

boost::tuple<int,std::string,double>

tup(42,"A four and a two",42.424242);

print_all(tup);

}

In the example, a helper class template, print_helper, is a metaprogram that visits all indices of a tuple, printing the element for each index The partial

specialization terminates the template recursion The function print_all

supplies the length of its tuple parameter, plus the tuple to a print_helper constructor The length of the tuple is retrieved like this:

boost::tuples::length<Tuple>::value

Trang 3

This is a constant integral expression, which means it can be passed as the second template argument for print_helper However, there's a caveat to our solution, which becomes clear when we see the output from running the program

42.4242

A four and a two

42

We're printing the elements in reverse order! Although this could be considered a feature in some situations (he says slyly), it's certainly not the intention here The problem is that print_helper prints the value of the

boost::tuples::length<Tuple>::value-1 element first, then the value of the previous element, and so on, until the specialization prints the first element's value Rather than using the first element as the special case and starting with the last element, we need to start with the first element and use the last

element as the special case How is that possible? The solution becomes apparent after you know that tuples are terminated with a special type,

boost::tuples:: null_type We can always be certain that the last type

in a tuple is null_type, which also means that our solution involves a

specialization or function overload for null_type

The remaining issue is getting the first element's value followed by the next, and so

on, and then stopping at the end of the list tuples provide the member functions get_head and get_tail to access the elements in them As its name suggests, get_head returns the head of the sequence of valuesthat is, the first element's value get_tail returns a tuple with all but the first value in the tuple That leads to the following solution for print_all

void print_all(const boost::tuples::null_type&) {}

template <typename Tuple> void print_all(const Tuple& t) {

std::cout << t.get_head() << '\n';

print_all(t.get_tail());

}

This solution is shorter than the original, and it prints the element values in the correct order Each time the function template print_all executes, it prints one element from the beginning of the tuple and then recurses with a tuple of all but the first value in t When there are no more values in the tuple, the tail is of

Trang 4

type null_type, the overloaded function print_all is called, and the

recursion terminates

It can be useful to know the type of a particular element such as when declaring variables in generic code that are initialized from tuple elements Consider a function that returns the sum of the first two elements of a tuple, with the

additional requirement that the return type must correspond to the largest type (for example, with regards to range of integral types) of the two Without somehow knowing the types of the elements, it would be impossible to create a general solution to this This is what the helper template element<N,Tuple>::type does, as the following example shows The problem we're facing not only involves calculating which element has the largest type, but declaring that type as the return value of a function This is somewhat complicated, but we can solve it using an extra level of indirection This indirection comes in the form of an additional helper template with one responsibility: to provide a typedef that defines the larger of two types The code may seem a little hairy, but it does the job

#include <iostream>

#include "boost/tuple/tuple.hpp"

#include <cassert>

template <bool B,typename Tuple> struct largest_type_helper {

typedef typename boost::tuples::element<1,Tuple>::type type;

};

template<typename Tuple> struct largest_type_helper<true,Tuple> {

typedef typename boost::tuples::element<0,Tuple>::type type;

};

template<typename Tuple> struct largest_type {

typedef typename largest_type_helper<

(sizeof(boost::tuples::element<0,Tuple>)>

sizeof(boost::tuples::element<1,Tuple>)),Tuple>::type type;

};

template <typename Tuple>

typename largest_type<Tuple>::type sum(const Tuple& t) {

typename largest_type<Tuple>::type

result=boost::tuples::get<0>(t)+

boost::tuples::get<1>(t);

return result;

}

int main() {

typedef boost::tuple<short,int,long> my_tuple;

Trang 5

boost::tuples::element<0,my_tuple>::type first=14;

assert(type_id(first) == typeid(short));

boost::tuples::element<1,my_tuple>::type second=27;

assert(type_id(second) == typeid(int));

boost::tuples::element<

boost::tuples::length<my_tuple>::value-1,my_tuple>::type

last;

my_tuple t(first,second,last);

std::cout << "Type is int? " <<

(typeid(int)==typeid(largest_type<my_tuple>::type)) << '\n';

int s=sum(t);

}

If you didn't quite follow the exercise in template metaprogramming, don't

worryit's absolutely not a requirement for utilizing the Tuple library Although this type of coding takes some time getting used to, the idea is really quite simple largest_type gets the typedef from one of the two helper class templates, largest_type_helper, where one version is partially specialized on the Boolean parameter This parameter is determined by comparing the size of the two first elements of the tuple (the second template parameter) The result of this is a typedef that represents the larger of the two types Our function sum uses that type as the return value, and the rest is simply a matter of adding the two elements The rest of the example shows how to use the function sum, and also how to

declare variables with types from certain tuple elements The first two use a hardcoded index into the tuple

boost::tuples::element<0,my_tuple>::type first=14;

boost::tuples::element<1,my_tuple>::type second=27;

The last declaration retrieves the index of the last element of the tuple, and uses that as input to the element helper to (generically) declare the type

boost::tuples::element<

boost::tuples::length<my_tuple>::value-1,my_tuple>::type last;

Tuples and for_each

The method that we used to create the print_all function can be extended to create a more general mechanism like std::for_each For example, what if we didn't want to print the elements, but rather wanted to sum them or copy them,

Trang 6

or what if we wanted to print only some of them? Sequential access to the tuple elements isn't straightforward, as we discovered when we developed the

preceding examples It makes sense to create a general solution that accepts a function or function object argument to invoke on the tuple elements This

enables not only the (rather limited) print_all function's behavior, but also that of any function that can accept the types of elements from a tuple The following example creates a function

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

TỪ KHÓA LIÊN QUAN