变长参数模版函数初探

来源:互联网 发布:如何用java编写小游戏 编辑:程序博客网 时间:2024/05/17 06:12

最开始在写一个 命令模块, 涉及到 简单命令 和 复合命令。
所有的命令 是通过字符串组装的。
命令的调用是通过注册机制 实现绑定的。
具体的功能封装在对应的 功能类里面。
由于复合命令的存在,会导致一条命令 执行多个处理。
所以希望在 注册的时候,能够直接将多个对象直接保存到一个容器内。
这就会涉及到 不定长参数 保存的 过程。
在这里我才用了变长参数模版。

我先定义一个通用的 key-value 的 变长模版, 用于构造一个容器对象。
指定 当输入类型 为 key-value:string-string时,对应的处理方法。
当然也可以指定其他类型的参数和对应的处理函数。

template<typename... Params>MapSet Register(string key, string value, Params... params) {    auto map_set = Register(params...);    map_set.add(key, value);    return map_set;}

设定模版扩展的终止条件

template<typename... Params>MapSet Register() {    return MapSet("null");}

这样 就能把想要的参数保存在对应的容器中。

在使用变长模版函数的过程中,我在想 每个函数都构造一个对象, 会导致接收的时候都调用拷贝构造。
所以我在定义容器的时候,定义了拷贝构造,和右值引用构造,方便查看调用过程。
最开始,我没有实现 右值引用,只是实现拷贝构造

    MapSet(const MapSet& map_set) {        dictory_ = map_set.dictory_;        index = AddRef();        cout << "construct from : const Copy, index :" << index << endl;    }    MapSet(MapSet& map_set) {        dictory_ = map_set.dictory_;        index = AddRef();        cout << "construct from : Copy, index :" << index << endl;    }

结果如图:
这里写图片描述

后来加入 右值引用

    MapSet(MapSet&& map_set) {        dictory_.swap(map_set.dictory_);        index = AddRef();        cout << "construct from : Swap, index :" << index << endl;    }}

结果如图:
这里写图片描述
发现 没有触发右值引用

再次修改代码

template<typename... Params>MapSet Register(string key, string value, Params... params) {    auto map_set = Register(params...);    map_set.add(key, value);    return std::move(map_set);}

结果如图:
这里写图片描述

现在已经触发了 右值引用, 其中8次构造 发生了 7次交换。
后来朋友告诉我 c++ 有返回值优化,于是 去掉std::move,把debug 编译 换成release 编译 再次尝试。

template<typename... Params>MapSet Register(string key, string value, Params... params) {    auto map_set = Register(params...);    map_set.add(key, value);    return map_set;}

结果如图:
这里写图片描述
这里产生2次构造,其中发生一次交换。

这里不同的编译器优化效果可能不一样,下面使用 blade 编译的
这里写图片描述

完整代码:

#include <iostream>#include <string>#include <map>using namespace std;int AddRef() {    static int ref = 0;    return ref++;}class MapSet{public:    MapSet(string info = "") {        index = AddRef();        cout << "construct from : " << info << ", index :" << index << endl;    }    MapSet(const MapSet& map_set) {        dictory_ = map_set.dictory_;        index = AddRef();        cout << "construct from : const Copy, index :" << index << endl;    }    MapSet(MapSet& map_set) {        dictory_ = map_set.dictory_;        index = AddRef();        cout << "construct from : Copy, index :" << index << endl;    }    MapSet(MapSet&& map_set) {        dictory_.swap(map_set.dictory_);        index = AddRef();        cout << "construct from : Swap, index :" << index << endl;    }    void add(string key, string value) {        dictory_.emplace(std::make_pair(key, value));    }    void print() {        cout << "output" << endl;        for (auto it : dictory_) {            cout << it.first << " : " << it.second << endl;        }    }private:    map<string, string> dictory_;    int index;};template<typename... Params>MapSet Register() {    return MapSet("null");}template<typename... Params>MapSet Register(string key, string value, Params... params) {    auto map_set = Register(params...);    map_set.add(key, value);    return map_set;}int main() {    Register("a", "a", "b", "b", "c", "c", "d", "d", "e", "e", "f", "f").print();    getchar();    return 0;}