模板与泛型 —— 可变参模板

2020-06-14  本文已影响0人  从不中二的忧伤
一、可变参函数模板
二、可变参类模板

C++ 11 中引入了 可变参模板 (Variadic Template): 允许模板中含有 0 个到 任意个 模板参数。

一、可变参函数模板

(1) 可变参函数模板的基本写法

template<typename... T>
void VarFunc(T... args)
{
    cout << sizeof...(T) << endl;
}

int main()
{
    VarFunc(1, 0.5, 'a', "abc");
    return 0;
}

(2) 递归函数展开参数包

// 递归终止函数
void VarFunc2()
{
    cout << "end" << endl;
} 

// 可变参函数模板 
template<typename T, typename... U>
void VarFunc2(const T& t, const U&... args)
{
    cout << t << endl;
    VarFunc2(args...);
}

int main()
{
    VarFunc2(1, 0.5, 'a', "abc");
    return 0;
}

二、可变参类模板

(1) 递归继承方式展开参数包

// 泛化可变参类模板 
template<typename... args>
class VarClass {};

// 全特化可变参类模板基类 
template<>
class VarClass<>
{
public:
    VarClass()
    {
        cout << "VarClass<>(), this = " << this << endl;
    }
};

// 偏特化可变参类模板 
template<typename val, typename... args>
class VarClass<val, args...> : private VarClass<args...> 
{
public:
    VarClass(val v, args... vs) : m_i(v), VarClass<args...>(vs...)
    {
        cout << "VarClass<val, args...>, this = " << this << endl;
        cout << v << endl;
    }
    val m_i;
};


int main()
{
    VarClass<int, double, string> v(1, 2.5, "abc");
        
    return 0;
}

输出结果:


image.png

在实例化 VarClass<int, double, string> v(1, 2.5, "abc") 时,编译器相当于生成了以下的类:

// 泛化可变参类模板 
template<typename... args>
class VarClass {};

// 全特化可变参类模板基类 
template<>
class VarClass<>
{
public:
    VarClass()
    {
        cout << "VarClass<>(), this = " << this << endl;
    }
};

template<>
class VarClass<string> : private VarClass<>
{
public:
    VarClass(string val) : m_val(val), VarClass<>()
    {
        cout << "VarClass<string> : " << m_val << endl;
    }
    
    string m_val;
};

template<>
class VarClass<double, string> : private VarClass<string>
{
public:
    VarClass(double val, string arg1) : m_val(val), VarClass<string>(arg1)
    {
        cout << "VarClass<double, string>() : " << m_val << endl;
    }
    
    double m_val;
};


template<>
class VarClass<int, double, string> : private VarClass<double, string>
{
public:
    VarClass(int val, double arg1, string arg2) : m_val(val), VarClass<double, string>(arg1, arg2)
    {
        cout << "VarClass<int, double, string>() : " << m_val << endl;
    }
    
    int m_val;
};



(2) 递归组合方式展开方式展开参数包
组合关系:类与类之间的关系,其中一个类包含另一个类的对象。

// 组合关系
class B
{
    // todo...  
};

class A
{
public:
    B b;      // A 中包含B对象
};

通过递归组合方式展开参数包:

template<typename... Args>
class VarClass{};

template<typename Val, typename... Args>
class VarClass<Val, Args...>
{
public:
    VarClass(Val val, Args... args) : m_val(val), m_args(args...)
    {
        cout << "VarClass<Val, Args...>(), this : " << this << endl;
        cout << m_val << endl; 
    }
    
    Val m_val;
    VarClass<Args...> m_args;
};


int main()
{
    VarClass<int, double, string> var(1, 2.5, "hello");
    return 0;
}

输出结果:


image.png

实际上在实例化 VarClass<int, double, string> 时,编译器生成了以下几个类:

template<typename... Args>
class VarClass{};

template<>
class VarClass<string>
{
public: 
    VarClass(string val) : m_val(val)
    {
        cout << "VarClass<string>() : " << m_val << endl;
    }
    
    string m_val;
    VarClass<> m_args;
};

template<>
class VarClass<double, string>
{
public:
    VarClass(double val, string arg1) : m_val(val), m_args(arg1)
    {
        cout << "VarClass<double, string>() : " << m_val << endl;
    }
    
    double m_val;
    VarClass<string> m_args;
};


template<>
class VarClass<int, double, string>
{
public:
    VarClass(int val, double arg1, string arg2) : m_val(val) , m_args(arg1, arg2)
    {
        cout << "VarClass<int, double, string>() : " << m_val << endl;
    }
    
    int m_val;
    VarClass<double, string> m_args;
};

(3) 通过 tuple 和递归调用方式展开参数包
tuple (元组):各种类型元素的组合

#include <iostream>
#include <tuple>

using namespace std;

int main()
{
    tuple<int, char, string> t(1, 'a', "hello");
    cout << get<0>(t) << endl;
    cout << get<1>(t) << endl;
    cout << get<2>(t) << endl;
    
    return 0;
}

实现思路:计数器从0开始,每处理一个参数,计数器+1;直到把所有参数处理完成。最后使用一个模板偏特化,作为递归调用结束

// count从0开始统计, maxcount 表示参数数量 
template<int count, int maxcount, typename... T>
class MyTuple
{
public:
    static void TupleCount(const tuple<T...>& t)
    {
        cout << "value = " << get<count>(t) << endl;
        MyTuple<count + 1, maxcount, T...>::TupleCount(t);
    }
};

// 特化版本,结束递归调用 
template<int maxcount, typename... T>
class MyTuple<maxcount, maxcount, T...>
{
public:
    static void TupleCount(const tuple<T...>& t){}
};


template<typename... T>
void TupleFunc(const tuple<T...>& mytuple)
{
    MyTuple<0, sizeof...(T), T...>::TupleCount(mytuple) ;
}

int main()
{
    tuple<int, char, string> mytuple(1, 'a', "hello");
    TupleFunc(mytuple);
    
    return 0;
}
上一篇下一篇

猜你喜欢

热点阅读