zoukankan      html  css  js  c++  java
  • 第1章 函数模板:1.5 重载函数模板

    1.5 Overloading Function Templates

    1.5 重载函数模板

    Like ordinary functions, function templates can be overloaded. That is, you can have different function definitions with the same function name so that when that name is used in a function call, a C++ compiler must decide which one of the various candidates to call. The rules for this decision may become rather complicated, even without templates. In this section we discuss overloading when templates are involved. If you are not familiar with the basic rules of overloading without templates, please look at Appendix C, where we provide a reasonably detailed survey of the overload resolution rules.

    和普通函数一样,函数模板也可以被重载。就是说,相同的函数名可以有不同的定义:于是,当使用函数名称进行函数调用时,C++编译器必须决定究竟要调用哪个候选函数。即使在不考虑模板的情况下,做出该决定的规则也己经是相当的复杂。本节中,我们将讨论有关模板的重载问题。如果你对不含模板的重载的基本规则还不是很熟悉,那么请先阅读附录C,在那里我们对重载解析规则进行了很详细的叙述。

    The following short program illustrates overloading a function template:

    下面的简短程序叙述了如何重载一个函数模板:

    // maximum of two int values:(求两个整数的最大值)
    int max (int a, int b)
    {
        return b < a ? a : b;
    }
    
    // maximum of two values of any type:(求任意类型两个数的最大值)
    template<typename T>
    T max (T a, T b)
    {
        return b < a ? a : b;
    }
    
    int main()
    {
        ::max(7, 42); // calls the nontemplate for two ints(调用两个int参的非模板函数)
        ::max(7.0, 42.0); // calls max<double> (by argument deduction)
        ::max(’a’, ’b’); //calls max<char> (by argument deduction)
        ::max<>(7, 42); // calls max<int> (by argument deduction)
        ::max<double>(7, 42); // calls max<double> (no argumentdeduction)
        ::max(’a’, 42.7); //calls the nontemplate for two ints
    }

    As this example shows, a nontemplate function can coexist with a function template that has the same name and can be instantiated with the same type. All other factors being equal, the overload resolution process prefers the nontemplate over one generated from the template. The first call falls under this rule:

    如示例所示,一个非模板函数可以和一个同名的函数模板同时存在,而且该该函数模板还可以被实例化为这个非模板函数。同等条件下,重载解析过程通常会调用非模板函数,而不是调用模板产生出的实例。第1个调用就符合这个规则:

    ::max(7, 42); // both int values match the nontemplate function perfectly

    If the template can generate a function with a better match, however, then the template is selected. This is demonstrated by the second and third calls of max():

    然而,如果模板可以产生一个更好的匹配,那么将选择模板。这可以通过第2和第3个的max()调用来说明:

    ::max(7.0, 42.0); // calls the max<double> (by argument deduction)
    ::max(’a’, ’b’);  //calls the max<char> (by argument deduction)

    Here, the template is a better match because no conversion from double or char to int is required (see Section C.2 on page 682 for the rules of overload resolution).

    这里,模板具有更好的匹配,因为不需要从double或char到int型的转换(可见第682页的C.2节《重载解析规则》)

    It is also possible to specify explicitly an empty template argument list. This syntax indicates that only templates may resolve a call, but all the template parameters should be deduced from the call arguments:

    也可以显式指定一个空模板参数列表。此语法表明只有模板可以解析该调用,但所有的模板参数都应该从调用实参中推导出来。

    ::max<>(7, 42); // calls max<int> (by argument deduction)

    Because automatic type conversion is not considered for deduced template parameters but is considered for ordinary function parameters, the last call uses the nontemplate function (while ’a’ and 42.7 both are converted to int):

    因为模板是不允许自动类型转化的;但普通函数可以进行自动类型转换,所以最后一个调用将使用非模板函数('a'和42.7都被转化为int):

    ::max(’a’, 42.7); //only the nontemplate function allows nontrivial conversions

    An interesting example would be to overload the maximum template to be able to explicitly specify the return type only:

    一个有趣的例子是重载max的模板,以便只可以显式返回类型:

    template<typename T1, typename T2>
    auto max (T1 a, T2 b)
    {
        return b < a ? a : b;
    }
    
    template<typename RT, typename T1, typename T2>
    RT max (T1 a, T2 b)
    {
        return b < a ? a : b;
    }
    
     

    Now, we can call max(), for example, as follows:

    现在, 我们可以调用max(),示例如下:

    auto a = ::max(4, 7.2); // uses first template
    auto b = ::max<long double>(7.2, 4); // uses second template

    However, when calling:

    但是,当我们调用:

    auto c = ::max<int>(4, 7.2); // ERROR: both function templates match

    both templates match, which causes the overload resolution process normally to prefer none and result in an ambiguity error. Thus, when overloading function templates, you should ensure that only one of them matches for any call.

    两个模板都匹配,通常这将导致重载决议过程不选择任何一个,并且导致二义性错误。因此,当重载函数模板时,你必需确保在任何调用时,他们中只有一个与之匹配。

    A useful example would be to overload the maximum template for pointers and ordinary C-strings:

    下面这个更有用的例子将会为指针和普通的C字符串重载这个求最大值的模板。

    #include <cstring>
    #include <string>
    
    // maximum of two values of any type:
    template<typename T>
    T max (T a, T b)
    {
        return b < a ? a : b;
    }
    
    // maximum of two pointers:
    template<typename T>
    T* max (T* a, T* b)
    {
        return *b < *a ? a : b;
    }
    
    // maximum of two C-strings:
    char const* max (char const* a, char const* b)
    {
        return std::strcmp(b,a) < 0 ? a : b;
    }
    
    int main ()
    {
        int a = 7;
        int b = 42;
        auto m1 = ::max(a,b); // max() for two values of type int
    
        std::string s1 = "hey"; "
        std::string s2 = "you"; "
        auto m2 = ::max(s1,s2); // max() for two values of type std::string
    
        int* p1 = &b;
        int* p2 = &a;
        auto m3 = ::max(p1,p2); // max() for two pointers
    
        char const* x = hello"; "
        char const* y = "world"; "
        auto m4 = ::max(x,y); // max() for two C-strings
    }

    Note that in all overloads of max() we pass the arguments by value. In general, it is a good idea not to change more than necessary when overloading function templates. You should limit your changes to the number of parameters or to specifying template parameters explicitly. Otherwise, unexpected effects may happen. For example, if you implement your max() template to pass the arguments by reference and overload it for two C-strings passed by value, you can’t use the three-argument version to compute the maximum of three C-strings:

    注意,在max()的所有重载中,我们都是按值传递参数的。一般而言,在重载函数的时候,最好只是改变那些需要改变的内容:就是说,你应该把你的改变限制在下面两种情况:改变参数的数目或者显式指定模板参数。否则,就可能会出现非预期的结果。例如,对于原来使用传引用的max()模板,但现在重载基于C-strings的max模板是按值传递参数的,那么你就不能使用带3个参数版本的max模板来求C-strings的最大值。

    #include <cstring>
    
    // maximum of two values of any type (call-by-reference)
    template<typename T>
    T const& max(T const& a, T const& b)
    {
        return b < a ? a : b;
    }
    
    // maximum of two C-strings (call-by-value)求两个C字符串的最大值(按值传参)
    char const* max(char const* a, char const* b)
    {
        return std::strcmp(b, a) < 0 ? a : b;
    }
    
    // maximum of three values of any type (call-by-reference)
    template<typename T>
    T const& max(T const& a, T const& b, T const& c)
    {
        return max(max(a, b), c); // error if max(a,b) uses call-by-value
    }
    
    int main()
    {
        auto m1 = ::max(7, 42, 68); // OK
    
        char const* s1 = "frederic";
        char const* s2 = "anica";
        char const* s3 = "lucas";
        auto m2 = ::max(s1, s2, s3); //run-time ERROR
    }

    The problem is that if you call max() for three C-strings, the statement

    问题在于:如果你对3个C-strings调用max(),那么语句:

    return max (max(a,b), c);

    becomes a run-time error because for C-strings, max(a,b) creates a new, temporary local value that is returned by reference, but that temporary value expires as soon as the return statement is complete, leaving main() with a dangling reference. Unfortunately, the error is quite subtle and may not manifest itself in all cases.

    将产生一个运行期错误,这是因为对于C-strings而言,这里的max(a,b)产生了一个新的临时局部值,该值可能被外面的max(即三个参数的max)以传引用的方式返回,而该临时值在return语句结束后将立即失效,main()函数将保留悬垂引用。不幸的是,该错误非常隐蔽,可能无法在所有的情况下均显示出来。

    Note, in contrast, that the first call to max() in main() doesn’t suffer from the same issue. There temporaries are created for the arguments (7, 42, and 68), but those temporaries are created in main() where they persist until the statement is done.

    请注意,与此相反,在main()函数对max()的首次调用不会遇到相同的问题。会为参数(7、42和68)创建临时对象,但是那些临时对象是在main()中创建的,并且会持续存在,直至语句结束。

    This is only one example of code that might behave differently than expected as a result of detailed overload resolution rules. In addition, ensure that all overloaded versions of a function are declared before the function is called. This is because the fact that not all overloaded functions are visible when a corresponding function call is made may matter. For example, defining a three-argument version of max() without having seen the declaration of a special two-argument version of max() for ints causes the two-argument template to be used by the three-argument version:

    对于复杂的重载解析规则所产生的结果,这只是具有非预期行为的代码例子中的一例。此外,请确保在调用函数之前声明函数的所有重载版本。事实上,这是因为在进行相应的函数调用时并非所有的重载函数都是可见的。例如,定义一个具有3个参数max()版本,而且直到定义处还没看到一个具有两个int参数的重载max()版本的声明,那么这个具有3个int实参的max()调用将会使用具有2个参数的模板,而不会使用基于int的重载的普通max()函数。

    #include <iostream>
    
    // maximum of two values of any type:
    template<typename T>
    T max(T a, T b)
    {
        std::cout << "max<T>() 
    ";
        return b < a ? a : b;
    }
    
    // maximum of three values of any type:(求任意类型的3个值的最大者)
    template<typename T>
    T max(T a, T b, T c)
    {
        return max(max(a, b), c); // uses the template version even for ints
                                  //because the following declaration comes
                                  // too late:
    }
    
    // maximum of two int values:(求两个int值的最大者)
    int max(int a, int b)
    {
        std::cout << "max(int,int) 
    ";
        return b < a ? a : b;
    }
    
    int main()
    {
        ::max(47, 11, 33); // OOPS: uses max<T>() instead of max(int,int)
    }

    We discuss details in Section 13.2 on page 217.

    我们将在第217页的13.2节讨论这个细节。

  • 相关阅读:
    servlet的运行机制,转发和重定向
    http协议,servlet的生命周期
    junit,面向切面开发(动态代理),工厂设计模式,数据库连接池
    JDBC 连接mysql数据库
    20169201 2016-2017-2 《移动平台应用开发实践》 第七周学习总结
    20169201 2016-2017-2 《网络攻防实践》第七周学习总结
    20169201 2016-2017-2 《移动平台应用开发实践》 第六周学习总结
    20169201 2016-2017-2 《网络攻防实践》第六周学习总结
    20169201 2016-2017-2 《网络攻防实践》第五周学习总结
    20169201 2016-2017-2 《移动平台应用开发实践》 第五周学习总结
  • 原文地址:https://www.cnblogs.com/5iedu/p/12696691.html
Copyright © 2011-2022 走看看