C++的模板(十二):forward模板

标准库的std::forward模板有一个类型T参数。在实际使用时,T取什么值应该不存在疑惑:

class  A {
public:
        A() {}
        A(int n):n(n) {}
        template <class T> A(T &&a);
        void print(A &&a) { printf("A&&\n"); }
        void print(A &a) { printf("A&\n"); }
        void print(const A &a) { printf("const A&\n"); }
        int n;
};


template <class T> A::A(T &&a)
{
        printf("template %s(&&a): a ",__FUNCTION__);
        print(std::forward<T>(a));
        n= a.n+1;
}

这个例子中,复制构造函数写成了模板。呵呵,广义复制构造函数。这不是太可靠。不过这个例子不会乱传不可使用的类型T,这样写已经足够。在复制构造函数模板中,向重载的print()成员函数转发了参数a。模板并不清楚传给它的类型是哪种重载类型,因此转发给print(),让它打印出来。这里,forward模板携带的参数类型T,照抄模板的传入类型。

A  f(int n)
{
        A a;
        a.n=n;
        printf("A f(%d) return\n", n);
        return a;
}

A  g(int n)
{
        printf("A g(%d) return\n", n);
        return A(n);
}


int main()
{
        A a;  a.n=900;
        printf("f(100): \n");
        A b=f(100);
        printf("%d\n", b.n);
        printf("g(100): \n");
        A b1=g(100);
        printf("%d\n", b1.n);
        printf("*******\n");
        const A *pa= &a;
        A b2= *pa;
        printf("%d\n", b2.n);
        printf("c:");
        A c(a);
        printf("c.n=%d\n", c.n);
}

打印出来是这样的信息:

f(100):
A f(100) return
template A(&&a): a A&
template A(&&a): a A&&
102
g(100):
A g(100) return
template A(&&a): a A&&
template A(&&a): a A&&
102
*******
b2: 900
c:template A(&&a): a A&
c.n=901

f()和g()函数的"赋值"语句(赋值格式的初始化语句)各导致了2次复制构造函数调用。一次return语句向返回值复制,一次返回值向接收的变量复制。第2次都是移动构造,第一次在g()函数也是移动构造。

但是, b2并没有调用这个“广义复制构造函数”。如果没有显式定义复制构造函数,C++会自动生成一个。这里调用的正是C++自动生成那个。模板复制构造函数不影响C++自动生成构造函数。所以用“广义复制构造函数抓取const 引用”的设想落空了。为了证实这一点,可以塞给class A一个base类,在base里面打印复制构造函数。如果调用的是C++自动生成那个版本,会自动调用基类的对应的复制构造函数。也就是base(const base &b);

class base {
public:
        base(){}
        base(const base &b) { printf("copy constructor(const&)\n");}
        base(base &b) { printf("copy constructor(&)\n");}
        base(base &&b) { printf("copy constructor(&&)\n");}
};
class  A :public base{
public:
        A() {}
        A(int n):n(n) {}
        template <class T> A(T &&a);
        void print(A &&a) { printf("A&&\n"); }
        void print(A &a) { printf("A&\n"); }
        void print(const A &a) { printf("const A&\n"); }
        int n;
};

别的代码不变。运行结果提示,b2确实调用了C++自动生成的那个复制构造函数。所以复制构造函数模板不是很圆满。

例子中的print()打印了类型信息。这个信息很有用。虽然,print没有返回值,但可以让它有。

        int print(A &&a) { printf("A&&\n"); return 1; }
        int print(A &a) { printf("A&\n"); return 2;}
        int print(const A &a) { printf("const A&\n"); return 3;}
        

这样模板用forward转发一下,从返回值就可以知道自己参数是什么类型了。

template <class T> A::A(T &&a)
{
		int ret;
        printf("template %s(&&a): a ",__FUNCTION__);
        ret =print(std::forward<T>(a));
        switch (ret) {
       	//......
        }
        n= a.n+1;
}

这样就可以对不同的类型,做不同的处理。经过forward,模板是可以知道自己的传入类型。

意识到这种识别对任意类型的通用性,最终把这也写成了模板:

template <class T>
struct eval_forward_t {
        typedef typename std::remove_reference<T>::type noref;
        typedef typename std::remove_const<noref>::type type;

        static int eval(type &&a) {return 1;}
        static int eval(type &a) {return 2;}
        static int eval(const type &a) {return 3;}
};

template <class T> A::A(T &&a)
{
        printf("template %s(&&a): a ",__FUNCTION__);
        print(std::forward<T>(a));
        printf("eval_forward: %d\n",
                eval_forward_t<T>::eval(std::forward<T>(a)));
        n= a.n+1;
}

相关推荐

  1. C++模板():forward模板

    2024-07-20 23:16:02       18 阅读
  2. C++ 设计模式 Forward Declaration & Pimpl

    2024-07-20 23:16:02       44 阅读
  3. C++中模板

    2024-07-20 23:16:02       21 阅读
  4. C++:完美转发()(std::forward

    2024-07-20 23:16:02       28 阅读
  5. [C++提高编程]():模板--类模板

    2024-07-20 23:16:02       38 阅读
  6. C++模板(一):算法轨迹

    2024-07-20 23:16:02       17 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-20 23:16:02       57 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-20 23:16:02       60 阅读
  3. 在Django里面运行非项目文件

    2024-07-20 23:16:02       48 阅读
  4. Python语言-面向对象

    2024-07-20 23:16:02       59 阅读

热门阅读

  1. Kotlin协程最佳实践

    2024-07-20 23:16:02       13 阅读
  2. SQL Server的魔法工坊:打造数据库的自定义函数

    2024-07-20 23:16:02       22 阅读
  3. Qt判定鼠标是否在该多边形的线条上

    2024-07-20 23:16:02       15 阅读
  4. 什么是虹膜识别技术

    2024-07-20 23:16:02       15 阅读
  5. C++/Qt 信号与槽

    2024-07-20 23:16:02       19 阅读
  6. CentOS Mysql8 数据库安装

    2024-07-20 23:16:02       19 阅读
  7. ubuntu22.04下YOLOv5 TensorRT模型部署

    2024-07-20 23:16:02       17 阅读
  8. 前端面试题日常练-day98 【Less】

    2024-07-20 23:16:02       17 阅读