zoukankan      html  css  js  c++  java
  • 002 模板实参推断、重载与模板

    模板实参推断

    一、模板函数显示实参

    情况1:

    template <typename T1, typename T2, typename T3>
    T1 sum(T2 a, T3 b)
    {
        return a + b;
    }

    分析:调用的时候就需要指定T1的类型,如:sum<float>(1, 2); 于是sum函数的返回类型为float。

     情况2:

    template <typename T1, typename T2, typename T3> //糟糕的设计,用户必须指定所有的三个模板参数
    T3 sum(T1 a, T2 b) 
    {
        return a + b;
    }

    分析:对于sum<float>(1, 2); 现在这个调用里指定T1类型为float,但是实际传进来的是1(int类型),会进行隐式类型转换,将1转换为float. T2的类型也可以根据sum(1,2)调用的第二个实参推断出来,这里是可能会是int. 那么T3是什么类型呢?显然这里编译器无法推断T3的类型,需要在调用时指定才能推断:

    1.   sum<int, int, int>(1, 2); 这样T3就推断出来是int。 

    2. 在指定显示模板实参时指定的类型是和模板参数匹配的,顺序是一一对应的,如:

        •  使用 sum<int>(1, 2); 对上面的第一个模板进行调用,那么T1对应int,T2T3则通过推断得出。

        •  使用 sum<int>(1, 2); 对上面的第二个模板进行调用,那么T1对应的类型是int,T2可以根据实际穿进去的参数进行推断,这里2为int,那么T2类型就是int,那么编译器就无法知道T3的实际类型了。

     

     二、完美转发

    template<class T>
    void wrapper(T&& arg) 
    {
        // arg 始终是左值
        foo(std::forward<T>(arg)); // 转发为左值或右值,依赖于 T
    }  
    
    分析:
      1. 若对 wrapper() 的调用传递右值string ,则推导 T 为 std::string(非string& 或string&& ,且 std::forward 确保将右值引用传递给 foo.
      2. 若对 wrapper() 的调用传递 const 左值string ,则推导 T 为 const string& ,且 std::forward 确保将 const 左值引用传递给 foo.
      3. 若对 wrapper() 的调用传递非 const 左值string ,则推导 T 为string& ,且 std::forward 确保将非 const 左值引用传递给 foo. 

    分析:

    1. 若对 wrapper() 的调用传递右值string ,则推导 T 为 std::string(非string& 或string&& ,且 std::forward 确保将右值引用传递给 foo.

    2. 若对 wrapper() 的调用传递 const 左值string ,则推导 T 为 const string& ,且 std::forward 确保将 const 左值引用传递给 foo.

    3. 若对 wrapper() 的调用传递非 const 左值string ,则推导 T 为string& ,且 std::forward 确保将非 const 左值引用传递给 foo.

     举例

     1 #include<iostream>
     2 #include<utility>
     3 using namespace std;
     4 
     5 void g(int &&i, int &j)
     6 {
     7     cout << i << " " << j << endl;
     8 }
     9 
    10 void f(int v1, int &v2)
    11 {
    12     cout << v1 << " " << ++v2 << endl;
    13 }
    14 
    15 //flip1实现不完整:顶层const和引用都丢掉了
    16 template <typename F, typename T1, typename T2>
    17 void flip1(F f, T1 t1, T2 t2)   
    18 {
    19     f(t2, t1);
    20 }
    21 
    22 template <typename F, typename T1, typename T2>
    23 void flip2(F f, T1 &&t1, T2 &&t2)
    24 {
    25     f(t2, t1);
    26 }
    27 
    28 template <typename F, typename T1, typename T2>
    29 void flip(F f, T1 &&t1, T2 &&t2)
    30 {
    31     f(std::forward<T2>(t2), std::forward<T1>(t1));
    32 }
    33 
    34 int main()
    35 {
    36     int i = 0, j = 0, k = 0, l = 0;
    37     cout << i << " " << j << " " << k << " " << l << endl;
    38     f(42, i);         //f改变其实参i
    39     flip1(f, j, 42);  //通过flip1调用f不会改变j
    40     flip2(f, k, 42);  //正确:k被改变了
    41     g(42, i);
    42     flip(g, i, 42);   //正确:第三个参数的右值属性被保留了
    43     cout << i << j << " " << k << " " << l << endl;
    44     return 0;
    45 }

    重载与模板

  • 相关阅读:
    大数加法、乘法实现的简单版本
    hdu 4027 Can you answer these queries?
    zoj 1610 Count the Colors
    2018 徐州赛区网赛 G. Trace
    1495 中国好区间 尺取法
    LA 3938 动态最大连续区间 线段树
    51nod 1275 连续子段的差异
    caioj 1172 poj 2823 单调队列过渡题
    数据结构和算法题
    一个通用分页类
  • 原文地址:https://www.cnblogs.com/sunbines/p/9375847.html
Copyright © 2011-2022 走看看