我曾在公司内部的一次技术培训课程中讲到如何展开可变模板参数的问题,具体来说是如何打印可变模板参数,我初略数了一下,有很多种,下面来看看到底有多少种不同的方法展开可变模板参数吧。

//展开变参的N种方法, 以print为例
//----写法1
template<typename T>
void print(T t)
{
cout << t << endl;
} template<typename T, typename... Args>
void print(T t, Args... args)
{
print(t);
print(args...);
}

  写法1很普通,没什么特别的,算是中规中矩,也是一般情况下的展开方式,下面来看特殊一点的展开方式:

//----写法2
template<typename T>
void printarg(T t)
{
cout << t << endl;
} template<typename... Args>
void print2(Args... args)
{
//int a[] = { (printarg(args), 0)... };
std::initializer_list<int>{(printarg(args), )...};
}

  写法2比较巧妙,借助初始化列表和逗号表达式来展开,在生成初始化列表的过程中展开参数包。这种方式不够间接,我希望能把printarg函数干掉,于是第三种方法出来了:

//----写法3
template<typename... Args>
void print3(Args... args)
{
std::initializer_list<int>{([&]{cout << args << endl; }(), )...};
}

template<typename... Args>
void expand(Args... args)
{
std::initializer_list<int>{(cout << args << endl, 0)...};
}

 

  写法3通过lambda表达式简化书写,非常间接直观,是我最喜欢的方式。那么除了这三种展开方式之外还有第4种吗?答案是肯定的。来看第4种写法:

//----写法4
template<std::size_t I = , typename Tuple>
typename std::enable_if<I == std::tuple_size<Tuple>::value>::type printtp(Tuple t)
{
//cout << "at range" << endl;
} template<std::size_t I = , typename Tuple>
typename std::enable_if<I < std::tuple_size<Tuple>::value>::type printtp(Tuple t)
{
std::cout << std::get<I>(t) << std::endl;
printtp<I + >(t);
} template<typename... Args>
void print4(Args... args)
{
printtp(std::make_tuple(args...));
}

  第4种写法也很巧妙,借助tuple和enable_if,通过不断地递增I来获取tuple中的元素并打印。至此已经完成4种写法了,还有没有第5种方法呢?答案还是肯定的。

//写法5
template <int N>
class printer {
public:
template<typename Tuple>
static void print(const Tuple& t)
{
//cout << std::get<N - 1>(t) << endl; //降序
printer<N->::print(t);
cout << std::get<N - >(t) << endl; //升序
}
}; template <>
class printer<> {
public:
template<typename Tuple>
static void print(const Tuple& t)
{
}
}; template<typename... Args>
void print5(const Args&... args)
{
auto tp = std::make_tuple(args...);
printer<sizeof...(args)>::print(tp);
}

  写法5的实现思路和写法4有异曲同工之妙,都是借助于int模板参数的递增来实现递归,不同的是写法是通过类模版的特化来实现递归的。已经5种了,还有第6种吗?看,第6种写法来了:

//写法6
template<int...>
struct IndexTuple{}; template<int N, int... Indexes>
struct MakeIndexes : MakeIndexes<N - , N - , Indexes...>{}; template<int... indexes>
struct MakeIndexes<, indexes...>
{
typedef IndexTuple<indexes...> type;
}; template<int ... Indexes, typename ... Args>
void print_helper(IndexTuple<Indexes...>, std::tuple<Args...>&& tup)
{
std::initializer_list<int>{([&]{cout << std::get<Indexes>(tup) << endl; }(), )...};
} template<typename ... Args>
void print6(Args... args)
{
print_helper(typename MakeIndexes<sizeof... (Args)>::type(), std::make_tuple(args...));
}

  第6种写法略显复杂,但很有意义,它实际上是进行了一个“氧化还原”反应,先将参数包转换为tuple,接着又将tuple转换为参数包,很有趣也很有用。至此,我们已经发现了6种展开可变模板参数的写法了,太棒了,你也许还兴犹未尽,还有第7种写法吗,有,但我已懒得再写了,其实还不止7种呢,那更多的写法在哪儿呢?在那儿,就在那儿等着你去发现……

/*****************更新***************/

将变参在展开过程中变为tuple<pair<...>>

#define MAKE_PAIR(text) std::pair<std::string, decltype(text)>{#text, text}

template<typename T, typename T1, typename... Args>
constexpr static inline auto apply(T const & t, const T1& first, const Args&... args)
{
return apply(std::tuple_cat(t, std::make_tuple(MAKE_PAIR(first))), args...);
} template<typename T>
constexpr static inline auto apply(T const & args)
{
return args;
} #define META(...) auto meta(){ return apply(std::tuple<>(), __VA_ARGS__); }

play with variadic template的更多相关文章

  1. 编译器对C++ 11变参模板(Variadic Template)的函数包扩展实现的差异

    编译器对C++ 11变参模板(Variadic Template)的函数包扩展实现的差异 题目挺绕口的.C++ 11的好东西不算太多,但变参模板(Variadic Template)肯定是其中耀眼的一 ...

  2. C++11 : variadic templates(可变参数模板)

      Introduction: Before the possibilities of the new C++ language standard, C++11, the use of templat ...

  3. c++11-17 模板核心知识(十二)—— 模板的模板参数 Template Template Parameters

    概念 举例 模板的模板参数的参数匹配 Template Template Argument Matching 解决办法一 解决办法二 概念 一个模板的参数是模板类型. 举例 在c++11-17 模板核 ...

  4. 如何设计一门语言(八)——异步编程和CPS变换

    关于这个话题,其实在(六)里面已经讨论了一半了.学过Haskell的都知道,这个世界上很多东西都可以用monad和comonad来把一些复杂的代码给抽象成简单的.一看就懂的形式.他们的区别,就像用js ...

  5. 实现一个 Variant

    很多时候我们希望能够用一个变量来保存和操作不同类型的数据(比如解析文本创建 AST 时保存不同类型的结点),这种需求可以通过继承来满足,但继承意味着得使用指针或引用,除了麻烦和可能引起的效率问题,该做 ...

  6. c++ 相关的技术资源整理归类

    最近一段时间 c++ 社区里最火热的话题莫过于 cppcon2015 了, isocpp 上一堆相关的新闻,其中有一个页面罗列了该会议的全部主题, 匆匆一瞥几乎眼花缭乱,为期一个星期的会议竟有上百个演 ...

  7. c++ 模板元编程的一点体会

    趁着国庆长假快速翻了一遍传说中的.大名鼎鼎的 modern c++ design,钛合金狗眼顿时不保,已深深被其中各种模板奇技淫巧伤了身...论语言方面的深度,我看过的 c++ 书里大概只有 insi ...

  8. 类型安全且自动管理内存的返回 std::string 的 sprintf 实现

    在这篇博文里,我提到了一个例子,说的是使用C++实现类型安全的printf.这个例子很惊艳,但是在我写程序的时候,并非那么"迫切"地需要它出现在我的工具箱中,因为它并不比普通的pr ...

  9. C++11的一些新特性

    3.1.9崭新的Template特性 Variadic Template 可变参数模板 void print() { } template <typename T, typename… Type ...

随机推荐

  1. 图片MassiGra045 简体中文|MG

    Window自带的图片打开,加载很缓慢.今天推荐一款日本的急速打开图片MassiGra045 简体中文化,简称MG 下载地址: http://pan.baidu.com/s/1qYFgRiW 密码: ...

  2. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其它一些编程语言中的 lambdas 比較类似。

    闭包是功能性自包括模块,能够在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其它一些编程语言中的 lambdas 比較相似.  闭包能够 捕获 和 ...

  3. 在发送信息时应用PendingIntent.FLAG_UPDATE_CURRENT

    1. 连续发送两条信息时,出现bug.以下是bug现象描述. 发送第一条信息,sentReceiver弹出toast告知发送成功,同时在listview中的发送状态立即同步更新为发送成功. 继续发送第 ...

  4. <转>LUA语法分析

    本文选自:http://www.cnblogs.com/nazhizq/p/6516561.html 一步步调试,在lparser.c文件中luaY_parser函数是语法分析的重点函数,词法分析也是 ...

  5. 【AI】Computing Machinery and Intelligence - 计算机器与智能

    [论文标题] Computing Machinery and Intelligence (1950) [论文作者] A. M. Turing (Alan Mathison Turing) [论文链接] ...

  6. linux shell 脚本攻略学习15--如何只列出目录,如何快速切换目录

    工作中经常遇到关于目录方面的问题,例如,如何只列出当前目录下的所有目录,以及如何快速高效的切换目录,而不需要使用鼠标,下面将简单介绍关于这两方面的解决方案: 一.如何只列出目录? 看似简单的任务,其实 ...

  7. 简单解决XP共享连接数10限制(转)

    1.建立一个txt文件,在里面输入以下文字:net session /delete /y,并将其保存为clear session.bat文件.net session用于查看本机共享的会话详细情况,可以 ...

  8. nRF2401A/nRF24L01/nRF24L01+无线模块最常见问题汇集(转)

    俗话说:每个人一生下来什么都会的,都是通过自己努力和探索出来的,NRF系列芯片,刚开始都好奇心加兴趣才来捣鼓它的,刚开始做硬件和软件,没有收发数据弄得整个人头都快炸开了,所以在此和大家分享一下前辈的经 ...

  9. ubuntu源列表(清华,阿里,官方,选一即可)

    Ubuntu的源列表在/etc/apt/sources.list中,替换即可 #清华的源deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial m ...

  10. SQL2000的系统表sysproperties在SQL2005中 无效的 问题

    有两种解决办法 方法一.是我在网上找的:将原来的sysproperties改成sys.extended_properties并且对应关系如下 sys.extended_properties left ...