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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值