您的位置:首页 > 编程语言

模板元编程(1):完美转发和变长模板

2018-02-28 18:57 218 查看
#include <iostream>
#include <typeinfo>
#include <type_traits>

using namespace std;

struct A {
A() {}
A(const A& a) { cout << "Copy Constructed " << __func__ << endl; }
A(A&& a) { cout << "Move Constructed " << __func__ << endl; }
};

struct B {
B() {}
B(const B& b) { cout << "Copy Constructed " << __func__ << endl; }
B(B&& b) { cout << "Move Constructed " << __func__ << endl; }
};

template <typename... T> struct MultiTypes; //先声明变长结构体模板的存在

template <typename T1, typename... T>
struct MultiTypes<T1, T...> : public MultiTypes<T...> {
T1 t1;
MultiTypes<T1, T...>(T1 a, T... b) : t1(a), MultiTypes<T...>(b...) {
cout << "get inside " << __func__ << endl;
cout << "MultiTypes<T1, T...>(T1 a, T... b)" << endl;
}
};

//全特化,并且是变长参数包递归的出口
template<>
struct MultiTypes<> {
MultiTypes<>() { cout << "get inside final MultiTypes()"<< endl;
cout << "MultiTypes<>()" << endl; }
};

//完美转发的变长模板,该转发函数的模板形参包含一个变长模板
template <template <typename...> class VariadicType, typename... Args>
VariadicType<Args...> Build(Args&&... args)  //Args&&...这种解包方式,将会把每一个arg_n变成Argn&&,引用折叠规则
{
cout << "get inside " << __func__ << endl;
return VariadicType<Args...>(forward<Args>(args)...);
}

template <template <typename...> class VariadicType, typename... Args>
VariadicType<Args...> NewBuild(Args... args)  //取消完美转发的&&解包方式,来看看情况
{
cout << "get inside " << __func__ << endl;
return VariadicType<Args...>(forward<Args>(args)...);
}

int main()
{
A a;
B b;

/*****
采用完美转发的方式来调用
****/
cout << typeid(Build<MultiTypes>(a, b)).name() << endl; //采用了模板参数自动推导,而返回值类型必须显式实例化
MultiTypes<A&, B&>  c = Build<MultiTypes>(a, b);
cout << typeid(c.t1).name() << endl;  //因为Arg&&这种完美转发的引用折叠使用,导致了实际的返回值类型
//不是MultiTypes<A, B>,而是MultiTypes<A&, B&>,这直接导致MultiTypes内的t1类型并非A或B,而是结构体引用类型A&,
//这也是为什么在MultiTypes内部并没有出现调用A或B的拷贝构造或移动构造函数的原因,而是直接调用了=赋值符号即可

MultiTypes<A, B> d = NewBuild<MultiTypes>(a, b); //应该会触发拷贝构造函数的调用
/**
1. a/b --> NewBuild<MultiTypes>(a, b); 形参拷贝赋值,对应第一次的A B拷贝
2. NewBuild<MultiTypes>(a, b) --> return VariadicType<Args...>(forward<Args>(args)...); 模板函数内部,由于实例化时不具名形参作为右值,对应第一组的移动构造
3. MultiTypes<A,B>(a,b): t1(a),MultiTypes<B>(b)
4. MultiTypes<B>(b):t1(b), MultiTypes<>()
**/

return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息