美文网首页
模板与泛型 —— 可变参模板

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

作者: 从不中二的忧伤 | 来源:发表于2020-06-14 18:53 被阅读0次
    一、可变参函数模板
    二、可变参类模板

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

    一、可变参函数模板

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

    • T为可变参类型,是0到n个不同的类型
    • args为可变形参,是对应的不同类型的参数
    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> → VarClass<double, string> → 继承于 → VarClass<string> → VarClass<>

    在实例化 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> → VarClass<double, string> → VarClass<string> → VarString<>

    实际上在实例化 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;
    }
    

    相关文章

      网友评论

          本文标题:模板与泛型 —— 可变参模板

          本文链接:https://www.haomeiwen.com/subject/nsffxktx.html