C++ variadic template

#include <vector>
#include <iostream>
#include <tuple>
#include <type_traits>
using namespace std;

template <typename Arg>
void process_recursion(Arg&& arg) {

    bool lb = std::is_rvalue_reference<decltype(arg)>::value;
    if (lb) {
        std::cout << "右值=" << arg << ",";
    }
    else {
        std::cout << "左值=" << arg << ",";
    }
}

template <typename First , typename... Rest>
void process_recursion(First&& first, Rest&&... rest) {

    bool lb = std::is_rvalue_reference<decltype(first)>::value;
    if (lb) {
        std::cout << "右值=" << first << ",";
    }
    else {
        std::cout << "左值=" << first << ",";
    }

    process_recursion(rest...);
}

int main() {
    int a = 0;
    process_recursion(1,a);
}

 typename ... Args是变长参数包,Args... args是最简单的一种拆包形式。

对于函数模板 template < typename... Args >  void test(Args... args); 

当调用test(1,'F')时,依次进行实参推演,1被推演成int,‘F’被推演成char,则模板函数被具体化为void test(int ,char);

拆包还有更多的变化,对于template < typename... Args >  void test(Args&&... args); 按照万能引用规则拆包。规则见《Effective Modern C++》条款1.

当调用int x=0; test(x,'F')时,依次进行实参推演,x被推演成int&,‘F’被推演成char&& , 则模板函数被具体化为void test(int& ,char&&);

 

1 template <typename... Types> void func1(std::vector<Types...> v1);   
2 
3 template <typename... Types> void func2(std::vector<Types>... v2);  

对于func1, 只有1个参数v1,Types...拆包成vector类的两个模板参数(一个是所容纳的元素类型,另一个是分配器类型)

对于func2,可能有0个或任意多个参数。例如:func2( std::vector<int> ,  std::vector<int>, std::vector<char>   );

由上可知,依次对多个可变模板参数处理,用到递归的方式处理比较繁琐,而且要注意递归的终结节点的确立。

下面给出一个迭代的方式处理多个模板参数。

template<typename T>
void print_arg(T t)
{
    std::cout  << t <<  std::endl;
}

template<typename... Args>
void print2(Args... args)
{
    int tmp[] = { (printarg(args), 0)... };
}

int main() {
    int x = 0;
    print2(1,x,7);
}

逗号表达式,逗号分割的各个子表达式依次求值,因此能产生调用函数的效果。

解包后的伪代码为int tmp[] = { (printarg(1),0), (printarg(x),0),(printarg(7),0)  };

为此方便的技巧,C++17特意的提供语言级别的comma fold expression

template<typename T>
void print_arg(T&& t)
{
    if constexpr (std::is_rvalue_reference<decltype(t)>::value)
        std::cout << "右值=" << t <<  std::endl;
    else
        std::cout << "左值=" << t <<  std::endl;
}

template<typename... Args>
void print2(Args&&... args)
{
    //int tmp[] = { (printarg(args), 0)... };
    (print_arg(std::forward<Args>(args)), ...);
}
int main() {
    int x = 0;
    print2(1,x,7);
}

此处,我们改进了一步,还额外提供完美转发能力

 

#include <iostream>  
using namespace std;

template<typename Arg>
void do_one(Arg arg) {
    std::cout << "," << arg ;
}

template<typename First, typename ...Rest>
void values(First first, Rest... rest) {

    std::cout << "values("<< first; 

    ( do_one(rest) , ... );

    std::cout << ")" << std::endl;
}

int main()
{
    values(1, 2, 3);
}

应用:SQL语句的拼装,values子句就是大量不同类型,可变个数的数据拼接,使用C++17的新可变模板技术,SQL封装库将更方便。

 

原文链接: https://www.cnblogs.com/thomas76/p/8505578.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    C++ variadic template

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/397596

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月11日 上午9:16
下一篇 2023年4月11日 上午9:39

相关推荐