本 Wiki 开启了 HTTPS。但由于同 IP 的 Blog 也开启了 HTTPS,因此本站必须要支持 SNI 的浏览器才能浏览。为了兼容一部分浏览器,本站保留了 HTTP 作为兼容。如果您的浏览器支持 SNI,请尽量通过 HTTPS 访问本站,谢谢!
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录前一修订版 | |||
cs:programming:cpp:cpp_primer:answers:chpt_16 [2024/01/14 13:46] – 移除 - 外部编辑 (未知日期) 127.0.0.1 | cs:programming:cpp:cpp_primer:answers:chpt_16 [2024/01/14 13:46] (当前版本) – ↷ 页面programming:cpp:cpp_primer:answers:chpt_16被移动至cs:programming:cpp:cpp_primer:answers:chpt_16 codinghare | ||
---|---|---|---|
行 1: | 行 1: | ||
+ | ======Chapter.16====== | ||
+ | Answers for chapter 16 | ||
+ | ---- | ||
+ | ====Ex.16.1-16.10==== | ||
+ | ==ex.16.1== | ||
+ | > | ||
+ | Class or function generated by the compiler from a template. | ||
+ | ==ex.16.2== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.3== | ||
+ | > | ||
+ | <code bash> | ||
+ | In file included from unit_test.cc: | ||
+ | ex_16_2.h: In instantiation of ‘int compare(const T&, const T&) [with T = Sales_data]’: | ||
+ | unit_test.cc: | ||
+ | ex_16_2.h: | ||
+ | 25 | if(v1 < v2) return 1; | ||
+ | | | ||
+ | ex_16_2.h: | ||
+ | 26 | if(v2 < v1) return -1; | ||
+ | | | ||
+ | </ | ||
+ | ==ex.16.4== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.5== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.6== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.7== | ||
+ | > | ||
+ | [[https:// | ||
+ | ==ex.16.8== | ||
+ | > | ||
+ | When implementing functions with templates, we should attempt to minimize the number of requirements placed on the argument types. From this perspective, | ||
+ | For instance, when dealing with most of the containers, we rely on iterators to operate them over a subscription. The reason for this is that only a few containers support subscript operations, while most support iterator dereferencing. Since iterators are definitely helpful to operate the containers at this point, we need to use equality operators instead of relational operators between them since most of the iterators do not define the relational operators. In this way, we can avoid to worry about the precise type of container we are processing, to a large extent. | ||
+ | ==ex.16.9== | ||
+ | > | ||
+ | * **function template**:A function template is a formula from which we can generate type-specific versions of that function. | ||
+ | * **class template**:A class template is a blueprint for generating classes. | ||
+ | Important distinct:class templates differ from function templates in that the compiler cannot deduce the template parameter type(s) for a class template. | ||
+ | |||
+ | ==ex.16.10== | ||
+ | > | ||
+ | When the compiler instantiates a class from our class template, it rewrites the class template, replacing each instance of the template parameter | ||
+ | ====Ex.16.11-16.20==== | ||
+ | ==ex.16.11== | ||
+ | > | ||
+ | <code cpp> | ||
+ | template < | ||
+ | template < | ||
+ | public: | ||
+ | List< | ||
+ | List< | ||
+ | List< | ||
+ | ~List(); | ||
+ | void insert(ListItem *ptr, elemType value); | ||
+ | private: | ||
+ | ListItem *front, *end; | ||
+ | }; | ||
+ | </ | ||
+ | In statement: | ||
+ | <code cpp> | ||
+ | void insert(ListItem *ptr, elemType value); | ||
+ | </ | ||
+ | and | ||
+ | <code cpp> | ||
+ | private: | ||
+ | ListItem *front, *end; | ||
+ | </ | ||
+ | the '' | ||
+ | ==ex.16.12== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.13== | ||
+ | > | ||
+ | I chose the one-to-one friend relationship in my case, since both operators deal with the instantiated '' | ||
+ | ==ex.16.14== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.15== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.16== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.17== | ||
+ | > | ||
+ | Generally, there is no difference between using the typename and class keywords. However, when we want to inform the compiler that a name represents a type, we must use the keyword '' | ||
+ | ==ex.16.18== | ||
+ | > | ||
+ | <code cpp> | ||
+ | //illegal, template parameter must be preceded by the keyword typename | ||
+ | a) template < | ||
+ | |||
+ | //illegal, The template parameter " | ||
+ | b) template < | ||
+ | |||
+ | //illegal, the inline keyword must follow the template parameter list. | ||
+ | c) inline template < | ||
+ | |||
+ | //illegal, the " | ||
+ | d) template < | ||
+ | |||
+ | //legal, but the char alias " | ||
+ | e) typedef char Ctype; | ||
+ | template < | ||
+ | </ | ||
+ | ==ex.16.19== | ||
+ | > | ||
+ | [[https:// | ||
+ | ==ex.16.20== | ||
+ | > | ||
+ | |||
+ | [[https:// | ||
+ | ====Ex.16.21-16.30==== | ||
+ | ==ex.16.21== | ||
+ | > | ||
+ | [[https:// | ||
+ | ==ex.16.22== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | '' | ||
+ | ==ex.16.23== | ||
+ | > | ||
+ | |||
+ | In the // | ||
+ | |||
+ | * The first shared-pointer manages the '' | ||
+ | |||
+ | * The second shared-pointer manages the '' | ||
+ | |||
+ | * The third shared-pointer handles the '' | ||
+ | ==ex.16.24== | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.25== | ||
+ | > | ||
+ | <code cpp> | ||
+ | 1. extern template class vector< | ||
+ | 2. template class vector< | ||
+ | </ | ||
+ | For statement 1: | ||
+ | * '' | ||
+ | * It cannot be define in the current header. | ||
+ | * It should be define where it needs to be instantiated. | ||
+ | * The compiler will not instantiate '' | ||
+ | For statement 2: | ||
+ | * '' | ||
+ | * Both its declaration and definition need to be put into the header file. | ||
+ | * If there is no using for the class template, it won't be instantiated. | ||
+ | * Any use of it in more than two other files will result in its instantiation for every single file. | ||
+ | ==ex.16.26== | ||
+ | > | ||
+ | No. | ||
+ | * The explicit instantiation will instantiate all its members. | ||
+ | * The default constructor of the element will be used for initializing the //vector//. | ||
+ | ==ex.16.27== | ||
+ | > | ||
+ | <code cpp> | ||
+ | template < | ||
+ | void f1(Stack< | ||
+ | class Exercise { | ||
+ | Stack< | ||
+ | Stack< | ||
+ | }; | ||
+ | int main() { | ||
+ | Stack< | ||
+ | f1(*sc); | ||
+ | int iObj = sizeof(Stack< | ||
+ | } | ||
+ | </ | ||
+ | An class instantiation require " | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | Refs: | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | ==ex.16.28== | ||
+ | > | ||
+ | |||
+ | **Header:** \\ | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | \\ **Test:** \\ | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | \\ **Deleter: | ||
+ | [[https:// | ||
+ | ==ex.16.29== | ||
+ | > | ||
+ | [[https:// | ||
+ | ==ex.16.30== | ||
+ | > | ||
+ | [[https:// | ||
+ | ====Ex.16.31-16.40==== | ||
+ | ==ex.16.31== | ||
+ | > | ||
+ | The custom deleter '' | ||
+ | ==ex.16.32== | ||
+ | > | ||
+ | During template argument deduction, the compiler uses types of the arguments in the call to find the template arguments that generate a version of the function that best matches the given call. | ||
+ | ==ex.16.33== | ||
+ | > | ||
+ | * Conversion to const for a reference parameter | ||
+ | * Array- or function to pointer conversions | ||
+ | ==ex.16.34== | ||
+ | >Given only the following code, explain whether each of these calls is legal. If so, what is the type of T? If not, why not? | ||
+ | <code cpp> | ||
+ | template <class T> int compare(const T&, const T&); | ||
+ | </ | ||
+ | <code cpp> | ||
+ | (a) compare(" | ||
+ | (b) compare(" | ||
+ | </ | ||
+ | '' | ||
+ | ==ex.16.35== | ||
+ | > | ||
+ | <code cpp> | ||
+ | template < | ||
+ | template < | ||
+ | double d; float f; char c; | ||
+ | </ | ||
+ | <code cpp> | ||
+ | a) calc(c, ' | ||
+ | b) calc(d, f); // legal. T is double | ||
+ | c) fcn(c, ' | ||
+ | d) fcn(d, f); // illegal. the arguments to T must have essentially the same type. d, f are different types and there is no conversion between them. | ||
+ | </ | ||
+ | ==ex.16.36== | ||
+ | > | ||
+ | <code cpp> | ||
+ | template < | ||
+ | template < | ||
+ | int i = 0, j = 42, *p1 = &i, *p2 = &j; | ||
+ | const int *cp1 = &i, *cp2 = &j; | ||
+ | </ | ||
+ | <code cpp> | ||
+ | a) f1(p1, p2); //T is int* | ||
+ | b) f2(p1, p2); //T1, T2 both are int* | ||
+ | c) f1(cp1, cp2); //T is pointer to const int | ||
+ | d) f2(cp1, cp2); //T1, T2 both are pointer to const int | ||
+ | |||
+ | // | ||
+ | //deduced conflicting types for parameter ‘T’ | ||
+ | e) f1(cp1, p1); | ||
+ | |||
+ | f) f2(p1, cp1); //T1 is int*, T2 is const int* | ||
+ | </ | ||
+ | [[https:// | ||
+ | ==ex.16.37== | ||
+ | > | ||
+ | Yes we can. We can specify the type we want to compare explicitly (int or double, or any other convertible type). Because explicit arguments follow the normal conversion rule, the parameter that doesn' | ||
+ | <code cpp> | ||
+ | int i = 1; | ||
+ | double d = 1.0; | ||
+ | auto ret = std:: | ||
+ | </ | ||
+ | |||
+ | ==ex.16.38== | ||
+ | > | ||
+ | The explicit argument that is passed to the make_shared function specifies the type of user-specific instants, that is, the type of the object that is allocated and the type of the smart pointer that is returned. | ||
+ | |||
+ | ==ex.16.39== | ||
+ | > | ||
+ | <code cpp> | ||
+ | // | ||
+ | //const char* works, but need to define the less operation | ||
+ | compare< | ||
+ | </ | ||
+ | ==ex.16.40== | ||
+ | > | ||
+ | <code cpp> | ||
+ | template < | ||
+ | auto fcn3(It beg, It end) -> decltype(*beg + 0) | ||
+ | { | ||
+ | // process the range | ||
+ | return *beg; // return a copy of an element from the range | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Legal, however: | ||
+ | * The element to which '' | ||
+ | * The operation '' | ||
+ | ====Ex.16.41-16.50==== | ||
+ | ==ex.16.41== | ||
+ | Exercise 16.41: Write a version of sum with a return type that is guaranteed to be large enough to hold the result of the addition. | ||
+ | <code cpp> | ||
+ | template < | ||
+ | auto | ||
+ | sum(T1 x, T2 y) -> | ||
+ | { | ||
+ | return x + y; | ||
+ | } | ||
+ | </ | ||
+ | ==ex.16.42== | ||
+ | > | ||
+ | <code cpp> | ||
+ | template < | ||
+ | int i = 0; const int ci = i; | ||
+ | |||
+ | a) g(i); // int&, lvalue -> T& -> T& && -> T& | ||
+ | b) g(ci); // const int&, const lvalue -> const T& -> const T& && -> const T& | ||
+ | c) g(i * ci); // int&&, | ||
+ | </ | ||
+ | ==ex.16.43== | ||
+ | > | ||
+ | <code cpp> | ||
+ | i; // lvalue int | ||
+ | cil; //const lvalue int | ||
+ | i = ci; // lvalue int. top const is ignored | ||
+ | g(i=ci); // lvaue int to T&& -> T& -> int& | ||
+ | </ | ||
+ | ==ex.16.44== | ||
+ | > | ||
+ | |||
+ | |||
+ | <code cpp> | ||
+ | /* T */ | ||
+ | a) g(i); // int | ||
+ | b) g(ci); // int, top const is ignored | ||
+ | c) g(i * ci); // int, top const is ignored | ||
+ | |||
+ | /* const T& */ | ||
+ | a) g(i); // int | ||
+ | b) g(ci); // int, const is already a part of function parameter type. | ||
+ | c) g(i * ci); // int, int&& | ||
+ | </ | ||
+ | ==ex.16.45== | ||
+ | > | ||
+ | <code cpp> | ||
+ | template < | ||
+ | </ | ||
+ | <code cpp> | ||
+ | int i = 0; | ||
+ | g(42); // v is vector< | ||
+ | g(i); // v is vector< | ||
+ | </ | ||
+ | ==ex.16.46== | ||
+ | > | ||
+ | <code cpp> | ||
+ | for (size_t i = 0; i != size(); ++i) | ||
+ | alloc.construct(dest++, | ||
+ | </ | ||
+ | * Overall, the loop constructed '' | ||
+ | * Code break down(assume template parameter type is T) | ||
+ | - '' | ||
+ | - '' | ||
+ | - The move template instantiated as ''< | ||
+ | - '' | ||
+ | - after '' | ||
+ | - '' | ||
+ | - move '' | ||
+ | ==ex.16.47== | ||
+ | > | ||
+ | [[https:// | ||
+ | ==ex.16.48== | ||
+ | > | ||
+ | [[https:// | ||
+ | ==ex.16.49== | ||
+ | > | ||
+ | <code cpp> | ||
+ | template < | ||
+ | template < | ||
+ | template < | ||
+ | template < | ||
+ | int i = 42, *p = &i; | ||
+ | const int ci = 0, *p2 = &ci; | ||
+ | g(42); | ||
+ | f(42); | ||
+ | </ | ||
+ | **Answer:** | ||
+ | // // | ||
+ | ^ Call ^ viable | ||
+ | | g(<color # | ||
+ | | g(<color # | ||
+ | | g(<color # | ||
+ | | g(<color # | ||
+ | | f(<color # | ||
+ | | f(<color # | ||
+ | | f(<color # | ||
+ | | f(<color # | ||
+ | ==ex.16.50== | ||
+ | > | ||
+ | [[https:// | ||
+ | ====Ex.16.51-16.60==== | ||
+ | ==ex.15.51== | ||
+ | > | ||
+ | <code cpp> | ||
+ | foo(i, s, 42, d); // 3 in Args, const (string&, | ||
+ | foo(s, 42, " | ||
+ | foo(d, s); // 1 in Args, const (string& | ||
+ | foo(" | ||
+ | </ | ||
+ | > | ||
+ | [[https:// | ||
+ | |||
+ | ==ex.15.53== | ||
+ | > | ||
+ | [[https:// | ||
+ | ==ex.15.54== | ||
+ | > | ||
+ | The program won't compile. Compiler couldn' | ||
+ | <code bash> | ||
+ | ex_16_53.cc: | ||
+ | 19 | return os << t << " | ||
+ | | | ||
+ | </ | ||
+ | ==ex.16.55== | ||
+ | > | ||
+ | the program won't compile: | ||
+ | <code bash> | ||
+ | ex_16_53.cc: | ||
+ | </ | ||
+ | <WRAP center round box 100%> | ||
+ | In books the author claims:\\ \\ | ||
+ | //A declaration for the nonvariadic version of print must be in scope when the variadic version is defined. Otherwise, the variadic function will recurse indefinitely.// | ||
+ | |||
+ | </ | ||
+ | |||
+ | An example from C++ template book might helpful to explain: | ||
+ | <code cpp> | ||
+ | template< | ||
+ | void print (T firstArg, Types… args) | ||
+ | { | ||
+ | std::cout << firstArg << ’\n’; | ||
+ | if (sizeof…(args) > 0) { //error if sizeof…(args)==0 | ||
+ | print(args…); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | <WRAP center round box 100%> | ||
+ | //However, this approach doesn’t work because in general both branches of all if statements in function templates are instantiated. Whether the instantiated code is useful is a run-time decision, while the instantiation of the call is a compile-time decision. For this reason, if you call the print() function template for one (last) argument, the statement with the call of print(args…) still is instantiated for no argument, and if there is no function print() for no arguments provided, this is an error.// | ||
+ | </ | ||
+ | ==ex.16.56== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.57== | ||
+ | > | ||
+ | |||
+ | The variadic version can handle multiple types at a time. | ||
+ | ==ex.16.58== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.59== | ||
+ | > | ||
+ | |||
+ | - '' | ||
+ | - '' | ||
+ | ==ex.16.60== | ||
+ | > | ||
+ | |||
+ | * '' | ||
+ | * The pack will be passed to the // | ||
+ | * Once the construction is complete, '' | ||
+ | ====Ex.16.61-16.67==== | ||
+ | ==ex.16.61== | ||
+ | > | ||
+ | |||
+ | [[https:// | ||
+ | ==ex.16.62== | ||
+ | > | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | ==ex.16.63== | ||
+ | > | ||
+ | [[https:// | ||
+ | ==ex.16.64== | ||
+ | See 16.63. | ||
+ | ==ex.16.65== | ||
+ | > | ||
+ | [[https:// | ||
+ | ==ex.16.66== | ||
+ | > | ||
+ | Specializations are limited by the form of the " | ||
+ | |||
+ | Hence, it depends on how generality can be abstracted from the problem we are trying to solve. In cases where there aren't too many things in common, overloading may be a good strategy. Otherwise, spending some time on the template is definitely worth it. | ||
+ | |||
+ | ==ex.16.67== | ||
+ | > | ||
+ | Specializations instantiate a template; they do not overload it. As a result, specializations do not affect function matching. |