• C++11_ Variadic Templates


    版权声明:本文为博主原创文章,未经博主允许不得转载。

    这次主要介绍C++11的又一个新特性 Variadic Templates (可变模板参数)

    它的实现类似于initializer_list<>,它可是使类模板接受一包参数

    本节主要应用递归的形式介绍 Variadic  Templates

    1.简单的调用

    #include <iostream>
    #include "string"
    
    using namespace std;
    
    void printX() {}//为了响应最后一次printX()的调用,因为这次没有传递参数,如果不声明不带参数的函数会报错
    
    template <typename T, typename... Types>
    void printX(const T& firstArg, const Types&... args)
    {
        cout<<firstArg<<endl;
        printX(args...);//递归调用
    }
    
    int main()
    {
        printX(1,2,3);
        return 0;
    }

     输出结果

    第一次调用printX()时传递的参数为(1,一包参数) 此时输出1 ,然后递归调用printX(args...)

    第二次调用printX()时传递的参数为(2,3) 此时输出结果为2,然后递归调用printX(3)

    第三次调用printX()时传递的参数为(3,) 此时输出结果为3,然后调用printX()  // 这就是声名不带参数的printX()的原因


    2. Variadic Templates的特性调用

    其实也不算Variadic Templates的特性调用,应该说所有的函数都具有这个特性

    #include <iostream>
    #include "string"
    
    using namespace std;
    
    
    void printX()
    {
        cout<<"C"<<endl;
    }
    
    template <typename... Types>
    void printX(const Types&... args)
    {
        cout<<"B"<<endl;
    }
    
    template <typename T, typename... Types>
    void printX(const T& firstArg, const Types&... args)
    {
        cout<<"A"<<endl;
    }
    
    int main()
    {
        printX(1);
        printX(1,2,3,4,5);
        printX();
        return 0;
    }

     输出结果

    总结: 编译器就喜欢调用有特点的函数(较特化的函数)...


     3.举几个Variadic Templates功能的例子


    a.   Variadic Templates 实现类似于 printf()的 函数

    #include <iostream>
    
    using namespace std;
    
    void printfA(const char *s)
    {
        while (*s)
        {
            if (*s == '%' && *(++s) != '%')
                throw std::runtime_error("invalid format string: missing arguments");
            std::cout << *s++ << std:: endl;;
        }
    }
    template<typename T, typename... Args>
    void printfA(const char* s, T value, Args... args)
    {
        while (*s)
        {
            if (*s == '%' && *(++s) != '%')
            {
                std::cout << value << std::endl;
                printfA(++s, args...); // call even when *s == 0 to detect extra arguments
                return;
            }
            std::cout << *s++ << std::endl;
        }
        throw std::logic_error("extra arguments provided to printf");
    }            
    //~~~~~~~~~~~~~~~
    
    int main()
    {
        int * pi = new int;
        printfA("%d%s%p%f
    ",
               10,
               "abc",
               pi,
               3.1415926
               );
        return 0;
    }

    输出结果

    第一次调用  printfA(%d%s%p%f , 10, args...)   输出10

    第二次调用  printfA(%s%p%f , "abc", args...)   输出abc

    第三次调用  printfA(%p%f , "pi", args...)      输出[地址]

    第四次调用  printfA(%f , "3.1415926", )      输出3.1415926

    ...


     b.Variadic Templates 递归创建,递归继承

    #include <iostream>
    
    using namespace std;
    
    
    template<typename Head, typename... Tail>
    class tuple<Head,Tail...>:private tuple<Tail...>
    {
        typedef tuple<Tail...> inherited;
    protected:
        Head m_head;
    public:
        tuple() {}
        tuple(Head v,Tail... vtail):m_head(v),inherited(vtail...){}//inheriter(vtail...)调用父类的构造函数
        auto head()->decltype(m_head){return m_head;}// Head head() { return m_head;}
        inherited& tail() {return * this;}
        
    };
    
    int main()
    {
        tuple<int, float, string> t{41, 6.3, "nico"};
        cout<< sizeof(t) <<endl;
        cout<< t.head() <<endl;
        cout<< t.tail().head()<<endl;
        cout<< t.tail().tail().head() <<endl;
        
        return 0;
    }

    输出结果

    使用递归继承的方式会将这些变量的储存地址连接起来


    c.sizeof...(args)的使用

    #include <iostream>
    
    using namespace std;
    
    
    template <int IDX, int MAX, typename... Args>
    struct PRINT_TUPLE {
        static void print (ostream& os, const tuple<Args...>& t) {
            os << get<IDX>(t) << (IDX+1==MAX ? "" : ",");
            PRINT_TUPLE<IDX+1, MAX, Args...>::print(os,t);
        }
    };
    // partial specialization to end the recursion
    template <int MAX, typename... Args>
    struct PRINT_TUPLE<MAX, MAX, Args...>   {
        static void print (std::ostream& os, const tuple<Args...>& t)  {
        }
    };
    // output operator for tuples
    template <typename... Args>
    ostream& operator<< (ostream& os,
                         const tuple<Args...>& t)
    {
        os << "[";
        PRINT_TUPLE<0, sizeof...(Args), Args...>::print(os,t); //sizeof...(args) 会获取参数个数
        return os << "]";
    }
    
    int main()
    {
        cout<<make_tuple(1.5,"abc",8,10)<<endl;
        return  0;
    }

     输出结果


    d.递归复合

    #include <iostream>
    
    using namespace std;
    
    template<typename... Values> class tup;
    template<> class tup<> { };
    template<typename Head, typename... Tail>
    class tup<Head, Tail...>
    {
        typedef tup<Tail...> composited;
    protected:
        composited m_tail;
        Head m_head;
    public:
        tup() { }
        tup(Head v, Tail... vtail)
        : m_tail(vtail...), m_head(v) { }
        Head head() { return m_head; }
        composited& tail() { return m_tail; }
    };
    
    int main()
    {
        tup<int, float, string> t1(41, 6.3, "nico");
        cout << sizeof(t1) << endl;          //12
        cout << t1.head() << endl;                    //41
        cout << t1.tail().head() << endl;            //6.3
        cout << t1.tail().tail().head() << endl;    //nico
        return 0;
    }

    输出结果 

     

    以上是Variadic Templates几个简单又实用的例子

    如有错误请指正

    参照<<侯捷 C++新标准 C++11>>

  • 相关阅读:
    npm 如何查看一个包的版本信息?
    npm使用常见问题及注意事项
    npm依赖管理:冗余,依赖树
    删除cnpm
    SQL Server 2012 读写分离设置
    SQL Server AlwaysOn读写分离配置
    Sql server Always On 读写分离配置方法
    Sqlserver 2012 Always on技术
    构建高性能web之路------mysql读写分离实战
    EJB配置jboss数据源
  • 原文地址:https://www.cnblogs.com/LearningTheLoad/p/7208680.html
Copyright © 2020-2023  润新知