C++_005_5 C++11: 变参模板和std::tuple

C++11: 变参模板和std::tuple

变参模板Variadic Templates

变参模板(Variadic Templates)顾名思义就是参数类型和个数可以改变的模板。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//定义
template<typename... Arguments>
class VariadicTemplate;
//实例化的方法
VariadicTemplate<double, float> instance;
VariadicTemplate<bool, unsigned short int, long> instance;
VariadicTemplate<char, std::vector<int>, std::string, std::string, std::vector<long long>> instance;
//参数个数甚至可以为0
VariadicTemplate<> instance;

//变参模板函数
template<typename... Arguments>
void SampleFunction(Arguments... parameters);
//使用
SampleFunction<int, int>(16, 24);
SampleFunction<std::string>("fun");

 

有人要问了这个省略号C语言里就有嘛,printf不就是不定参数的嘛。但是...但是,变参模板是类型安全的,而且它可以让类似功能的实现得到极大简化。这篇文章就 介绍了一个用变参模板实现的非常精巧的类型安全的printf, 还简要的说明了C++11引入这个特性的动机。我对模板元编程不甚了解,但是从大牛们用奇淫技巧实现的boost::mpl和boost::tuple来 模拟可变参数模板,不难看出这个功能对编写C++库的重要性。当然如果Concepts不被移出C++11标准,C++泛型能力会有翻天覆地的提高,不管怎样,C++11在语言层级增加了对变参模板支持,还是极大的增强了C++模板的抽象能力。

std::tuple

对于大多数程序员来说可能很少去编写模板库,但是新的可变参数的容器std::tuple大多数都会用到。tuple就是一个包含任意多个不同类型的数据成员的集合,就像一个增强版的std::pair。直接贴出一些用例,细节参照手册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// tuple example
#include <iostream>     // std::cout
#include <tuple>        // std::tuple, std::get, std::tie, std::ignore

int main ()
{
  std::tuple<int,char> foo (10,'x');
  auto bar = std::make_tuple ("test", 3.1, 14, 'y');

  std::get<2>(bar) = 100;                                    // access element

  int myint; char mychar;

  std::tie (myint, mychar) = foo;                            // unpack elements
  std::tie (std::ignore, std::ignore, myint, mychar) = bar;  // unpack (with ignore)

  mychar = std::get<3>(bar);

  std::get<0>(foo) = std::get<2>(bar);
  std::get<1>(foo) = mychar;

  std::cout << "foo contains: ";
  std::cout << std::get<0>(foo) << ' ';
  std::cout << std::get<1>(foo) << '\n';

  return 0;

 

实际中应用

虽然变参模板无比拉风,但是平时编程时却不容易用到,tuple灵活强大,但是只用在函数返回值上,也未免大财小用,而且用多了会降低代码的可读 性。在项目中,有需求要测试触发signal的功能,需要一个slot的mock,signal 可能传递不同个数不同类型的参数,终于"以权谋私"用上了Variadic Templates和tuple。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
template<typename... Args> 
class SignalReceiverMock {
public:
  SignalReceiverMock() : _slotCalled(false) {}

  void slot(Args... args) {
    _slotCalled = true;
    _arguments = std::make_tuple(args...);
  }

  bool slotCalled() {
    return _slotCalled;
  }

  bool argumentsPassedCorrectly(Args... args) {
    auto arguments = std::make_tuple(args...); 
    return arguments == _arguments;
  }

private:
  bool _slotCalled;
  std::tuple<Args...> _arguments;
};

//在测试中使用
SignalReceiverMock<std::string, int> receiver1;
SignalReceiverMock<> receiver2;
Signal1 signal1("test", 0); // singal1 有传递两个参数
Signal2 signal2(); //signal2 不传递参数
signal1.connect(boost::bind(&SignalReceiverMock<std::string, int>::slot, *receiver1, _1, _2));
signal2.connect(boost::bind(&SignalReceiverMock<>::slot, *receiver2));
....//触发signal的操作
testResult.asserTrue(receiver1.slotCalled() && receiver1.argumentsPassedCorrectly("test", 0));
testResult.asserTrue(receiver2.slotCalled());

 

 

C++

转载于:https://www.cnblogs.com/gudushishenme/p/3332582.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值