利用可变模板参数实现log功能

在以前的博文中,写过类似的课题。使用的是下面这种方法。

// 递归出口
template <typename T>
void logOld(const T& t)
{
    std::cout << t << ‘\n‘;
}

// 递归展开
template <typename T, typename ... Args>
void logOld(const T& t, const Args& ... args)
{
    std::cout << t << ‘ ‘;
    logOld(args...);
}

函数调用有递归,模板在展开的时候也可以有递归。在写递归函数时,我们需要找出递归的出口,这么不会陷入无限递归。同样,在运用模板展开时候递归同样需要考虑递归的出口。

为了实现随意log的输出,比如

    zz::logOld(1);
    zz::logOld(1, 2);
    zz::logOld(1, 2, ‘-‘, "Today");
    int a[4];
    zz::logOld("Hello", "World", 2016, ‘-‘, 3, ‘-‘, 19, a);

那么参数就是不可控的,但是在递归展开中,最后一个参数,肯定是递归的出口,如上面logOld函数定义所示。运行的效果:

但是,这种是递归实现,生成的代码也是嵌套的,性能方面有所损失,但是现实起来方便也很容易理解。

最近看了一些文章,关于可变参数模板的,有一些关于Parameter pack的文章,其中有关于Pack expansion的使用。

>

Pack expansio

A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the types from the pack, in order.

其就是提供一种多参数解包的模式,模式必须含有至少一个参数。

根据这个特性,我设计了以下的代码

template <typename T>
typename std::decay<T> unpack(const T& t)
{
    std::cout << t << ‘ ‘;
    typename std::decay<T> _ins;
    return _ins;
}

template <typename T, typename ... Args>
void debugLogImpl(const T& t, const Args& ... args)
{
    std::cout << t << ‘ ‘;
    auto _fun = [](...) {};
    _fun(unpack(args)...);
    std::cout << ‘\n‘;
}

unpack为解包一个参数的模式,unpack(args)…介绍多参数。

比如args为a,b,c,那么unpack(args)…等价于unpack(a), unpack(b), unpack(c)。这种形式的解包结果,我现在只想到了作为函数参数。所有我定义了一个lambda函数,其接受多参数,然后调用这个lambda函数来调用解包之后的unpack函数集合。

但是函数参数入栈的顺序是从右往左,那么先调用的是unpack(c),输出的也就是”c”,那么不行的。但是在C++14中我们可以直接

    (unpack(args), ...);

但是在C++11中,这是不可以的。我也没有找出这么顺序调用解包之后的函数的办法。为了解决这个log顺利不对的问题,无奈又写了一大段的特例模板。

template <typename T>
typename std::decay<T> unpack(const T& t)
{
    std::cout << t << ‘ ‘;
    typename std::decay<T> _ins;
    return _ins;
}

template <typename T, typename ... Args>
void debugLogImpl(const T& t, const Args& ... args)
{
    std::cout << t << ‘ ‘;
    auto _fun = [](...) {};
    _fun(unpack(args)...);
    std::cout << ‘\n‘;
}

template <typename T0>
void debugLog(const T0& t0)
{
    debugLogImpl(t0);
}

template <typename T0, typename T1>
void debugLog(const T0& t0, const T1& t1)
{
    debugLogImpl(t0, t1);
}

template <typename T0, typename T1, typename T2>
void debugLog(const T0& t0, const T1& t1, const T2& t2)
{
    debugLogImpl(t0, t2, t1);
}

template <typename T0, typename T1, typename T2, typename T3>
void debugLog(const T0& t0, const T1& t1, const T2& t2, const T3& t3)
{
    debugLogImpl(t0, t3, t2, t1);
}

...

template <typename T0, typename T1, typename T2, typename T3, typename T4
          , typename T5, typename T6, typename T7, typename T8, typename T9>
void debugLog(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4
              , const T5& t5 ,const T6& t6, const T7& t7, const T8& t8, const T9& t9)
{
    debugLogImpl(t0, t9, t8, t7, t6, t5,  t4, t3, t2, t1);
}

将参数调个个。

#define DEBUG_LOG(...) zz::debugLog(__VA_ARGS__)

定义一个宏,来统一对外口径。


int main()
{
//    zz::logOld(1);
//    zz::logOld(1, 2);
//    zz::logOld(1, 2, ‘-‘, "Today");
//    int a[4];
//    zz::logOld("Hello", "World", 2016, ‘-‘, 3, ‘-‘, 19, a);

    DEBUG_LOG(1);
    DEBUG_LOG(1, 2);
    DEBUG_LOG(1, 2, 3);
    DEBUG_LOG(1, ‘-‘, ‘a‘, 1, "sssss");

    return 0;
}

结果如下

然后就是

template <typename T>
typename std::decay<T> unpack(const T& t)
{
    std::cout << t << ‘ ‘;
    typename std::decay<T> _ins;
    return _ins;
}

这边为什么要用decay,如果不用向这样

template <typename T>
T unpack(const T& t)
{
    std::cout << t << ‘ ‘;
    return t;
}

对于这样的“ssssss”,其会报

/home/zhou/work/qt_project/zzLog/main.cpp:48: error: no matching function for call to ‘unpack(const char [6])‘
     _fun(unpack(args)...);

---
/home/zhou/work/qt_project/zzLog/main.cpp:36: error: function returning an array
                     ^

使用decay将数组退化为const char*来解决问题。

时间: 2024-10-13 22:43:35

利用可变模板参数实现log功能的相关文章

C++模板之可变模板参数

可变模板参数---- C++11新特性 可变模板参数(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数.任意类型的参数 由于可变模版参数比较抽象,使用起来需要一定的技巧,所以它也是C++11中最难理解和掌握的特性之一 参数包(parameter pack) 模板参数包,如: template<typename- Args>class tuple; Args标识符的左侧使用了省略号,在C++11中Args被称为"模板

C++ 遍历可变模板参数 iterate variadic template arguments

1 template<size_t I = 0, typename FuncT, typename ...Tp> 2 inline typename std::enable_if_t<I == sizeof ...(Tp)> for_each(std::tuple<Tp ...>&, FuncT) 3 { 4 } 5 6 template<size_t I = 0, typename FuncT, typename ...Tp> 7 inline t

C++ 11 可变模板参数的两种展开方式

#include <iostream> #include <string> #include <stdint.h> template<typename T> T Sum(T t) { std::cout << t << " = "; return t; } template<typename T, typename... Args> T Sum(T head, Args...args) { std::c

泛化之美--C++11可变模版参数的妙用

1概述 C++11的新特性--可变模版参数(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数.任意类型的参数.相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进.然而由于可变模版参数比较抽象,使用起来需要一定的技巧,所以它也是C++11中最难理解和掌握的特性之一.虽然掌握可变模版参数有一定难度,但是它却是C++11中最有意思的一个特性,本文希望带领读者由浅入深的认识和掌握这一特性

第20课 可变参数模板(1)_模板参数包和函数参数包

1.  参数包(parameter pack) (1)模板参数包(以tuple为例):template<typename- Elements>class tuple ①Elements标识符的左侧使用了省略号,在C++11中Elements被称为"模板参数包",表示可以接受任意多个参数作为模板参数. ②编译器将多个模板参数打包成"单个"的模板参数包,如tuple<int, char, double>实例化模板类时,Element就是包含int

创建函数利用可变参数列表的形式模拟实现printf的功能

★创建函数利用可变参数列表的形式模拟实现printf的功能. 模拟简单的输入单个字符和字符串时的输出形式 如:输入:%c %c %c %c %c\t%s,'h','e','l','l','o',"welcome to here!" 输出:h e l l o   welcome to here! #include<stdio.h> #include<stdlib.h> #include<stdarg.h>    //需引入stdarg的头文件以便建立可

利用smarty模板(登录、有关信息操作等功能)

注意:smarty模板前提是:前端和后端是分开的,所以肯定会有很多的后台页面,php页面和html页面是分开存储的!! 可以通过模板编写很多的功能,这里不是用的ajax方法写的,所以会刷新页面~~ 下面就开始编写各种页面的功能了!!! 一.登录页面的编写也是分两个页面(后台和前端) 1.首先是后台的php页面,很简单只要引入"入口文件",然后写出显示模板的方法就可以了. <?php include("../init.inc.php"); //引入入口文件 $s

C利用可变参数列表统计一组数的平均值,利用函数形式参数栈原理实现指针运算

//描述:利用可变参数列表统计一组数的平均值 #include <stdarg.h> #include <stdio.h> float average(int num, ...);//函数原型:即声明 float average2(int num, ...);//num个数 void add(int num, int x, int y, int z); int main(void){ int a=10; int b=20; printf("a地址:%p b地址:%p\n&

【Halcon示例001---varaition_model_single】 利用单张图像创建可变模板

1 * 2 * This example shows how to employ the new extensions of HALCON's variation model operators 3 * to perform customary print quality tests. 4 * In this example the variation model is built upon a single reference image. 5 * The example consists o