C ++ function template explain (a): the concept and characteristics

Function template refers to a class of functions: may be called with parameters of a plurality of different data types, represents a family of functions . Its appearance and normal function is very similar, the only difference is this: the function of some elements is undetermined, these elements will instantiate was only when in use. First look at a simple example:

First, the definition of a simple function template

The following example will define a template function that returns the largest of two parameters that one:

// 文件:"max.hpp"
template<typename T>
inline const T& max(const T& x, const T& y)
{
    return x < y ? y : x;
}

This template defines a function "return the largest of two values," the family of functions, the type of the parameter has not been determined, by the type of template parametersT determined. Template parameter is required to declare the following manner:

template< 模板参数列表 >

In this example, the template parameter list as follows: typename T. Keyword typenameintroduced Tthis type template parameter. Of course, you can use any identifier as the name of the template type parameter. We can use any type of (basic data type, class type) to instantiate the template function, as long as the type of data used to provide the operating functions required in the template. For example, in this example, the type Tneeded to support operator <, as a and b is through this comparison to the size of the operator.

For historical reasons, you can also use keywords classinstead typenameto define a template type parameter, but should be used as much as possible typename.

Second, use the function template

The following program uses this function template defined above:

#include <iostream>
#include <string>
#include "max.hpp"

using namespace std;

int main(int argc, char *argv[])
{
    cout << max(4, 3) << endl; // 使用int类型实例化了函数模板,并调用了该函数实例。
    cout << max(4.0, 3.0) << endl; // 使用double类型实例化了函数模板,并调用了该函数实例。
    cout << max(string("hello"), string("world")) << endl; // 使用string类型实例化了函数模板,
                                                           // 并调用了该函数实例。
    return 0;
}

Generally, not compiled into the template can handle any type of a single entity, but rather to the examples for each type of template function parameters are a function of generating a separate entity from the function template. Therefore, for each type, template code are compiled once. Such a template in place of the particular type of process parameter called to instantiate the template . It creates a new instance of the function (for instance with a different object in the programming).

If you try to instantiate a template based on the type that does not support the operation of the internal template used, it will trigger a compile-time error:

std::complex<double> c1, c2;
max(c1, c2); // 编译错误:std::complex并不支持运算符<

So: templates are compiled twice, occurred at:

  • Before template instantiation, see the syntax is correct, then may find that the missing semicolons.
  • During the template instantiation, the template code checks to see if all calls are valid. At this time, the call may be found to be invalid, for example, does not support some examples of the type of function calls and so on.

So this raises an important question: When using a template function and initiate template instantiation, the compiler must see the definition of the template . In fact, this is different from normal function, because for normal function, as long as the declaration of the function (do not even defined), can successfully compile period.

Third, the function template argument inferred

When we call a function reference template for some real, template parameters can be determined by our arguments passed.

Note: The function templates in inferring parameter type, automatic type conversions are not allowed, for each type of template parameters must correct match.

template<typename T>
inline const T& max(const T& x, const T& y)
{
    return x < y ? y : x;
}

int main()
{
    // 不能这样调用:
    // max(10, 20.0); // 错误,因为函数模板中的类型推断拒绝隐式类型转换
    // 这是因为,无法确定到底应该使用哪个参数类型来实例化这个模板函数。
    // 所以,C++拒绝了这种做法。 可用的解决方案:
    ::max(static_cast<double>(10), 20.0); // OK,因为两个参数都为double。
    ::max<double>(10, 20.0); // OK, 显示指定参数,这样可以尝试对参数进行类型转换。
    return 0;
}

Note: The template argument type inference is not suitable for return. Because the return type does not appear in the type parameter inside the function call.

Therefore, you must explicitly specify the return type:

template<typename T1, typename T2, typename RT>
inline RT func()
{
    // ...
    return RT();
}

int main(int argc, char *argv[])
{
    func<int>(); // 必须这样显示地指定返回类型才可以,无法进行自动类型推断。
    return 0;
}

Fourth, the function template overloading

And normal function, the function templates can be overloaded. In the following example, a function can be non-template and a template function with the same name exist, it is called specialized function template . And also the function template is instantiated as the non-template function.

// #1
inline const int& max(const int& a, const int& b)
{
    return a < b ? b : a;
}

// #2
template<typename T>
inline const T& max(const T& a, const T& b)
{
    return a < b ? b : a;
}

// #3
template<typename T>
inline const T& max(const T& a, const T& b, const T& c)
{
    return max(max(a, b), c);
}

int main(int argc, char *argv[])
{
    /*01*/max(7, 42, 68);       // 调用#3
    /*02*/max(7.0, 6.0);        // 调用#2
    /*03*/max('a', 'b');        // 调用#2
    /*04*/max(7, 42);           // 调用#1
    /*05*/max<>(7, 42);         // 调用#2
    /*06*/max<double>(7, 42);   // 调用#2但是没有推断参数
    /*07*/max('a', 42.7);       // 调用#1
    return 0;
}

Summarized as follows:

  • For non-template functions and function template of the same name, if other conditions are the same, then at the time of the call, overload resolution process will give priority to non-template function call without instantiating template ( 04 ).
  • If the template function can produce a better match, then select the template ( 02, 03 ).
  • You can also explicitly specify an empty template parameter list, tell the compiler: You must use a template to match ( 05 ).
  • Since the function template refusal implicit type conversion, so when all of the template can not match, but can be found to match a non-template function by the cast, the call that function ( 07 ).

Fifth, the function template overloading Notes

When overloaded function template, please keep in mind: to change the function declaration will be limited in the following two cases:

  • Changing the number of parameters
  • Parameter specifies the display template (i.e. template function specialization)

Otherwise, it may result in unintended consequences, such as in the following example, the template function is carried out using a reference parameter passing, however, in which a heavy load of (actually for specialized char * conducted), but use the values ​​passed way, which will lead to unexpected results:

template<typename T>
inline const T& max(const T& a, const T& b)
{
    return a < b ? b : a;
}

// #2: 存在隐患,因为其它的重载都是以引用传递参数,而这个重载版本
// 却使用了值传递,不符合上面介绍的需要遵守的两个可变条件。
inline const char* max(const char* a, const char* b)
{
    return std::strcmp(a, b) < 0 ? b : a;
}

template<typename T>
inline const T& max(const T& a, const T& b, const T& c)
{
    // 这里对max(a, b)的调用,如果调用了函数#2,
    // 那么将会返回一个局部的值,如果恰好这个局部的值
    // 又比c大,那么将会返回一个指向局部变量的指针,
    // 这是很危险的(非预期的行为)。
    return max( max(a, b), c );
}

int main()
{
    char str1[] = "frederic";
    char str2[] = "anica";
    char str3[] = "lucas";

    char* p1 = str1;
    char* p2 = str2;
    char* p3 = str3;

    // 这种用法是错的,这是因为:
    // max(a, b)返回的是一个指针,这个指针是一个局部的对象,
    // 并且这个局部的对象很有可能会被返回。
    auto result = max(p1, p2, p3);
    return 0;
}

Guess you like

Origin www.cnblogs.com/rosefinch/p/12294338.html