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

#include 
#include 
#include 

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 : public MultiTypes {
    T1 t1;
    MultiTypes(T1 a, T... b) : t1(a), MultiTypes(b...) {
        cout << "get inside " << __func__ << endl;
        cout << "MultiTypes(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 Build(Args&&... args)  //Args&&...这种解包方式,将会把每一个arg_n变成Argn&&,引用折叠规则
{
    cout << "get inside " << __func__ << endl;
    return VariadicType(forward(args)...);
}

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

int main()
{
    A a;
    B b;

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

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

    return 0;
}

模板元编程(1):完美转发和变长模板_第1张图片

你可能感兴趣的:(模板元编程)