• 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) << '
    ';
    
      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());
  • 相关阅读:
    网卡的ring buffer
    vm 缓存相关参数配置
    网卡TSO/GSO特性
    物理主机BIOS设置
    jquery_元素文本值、属性值的获取、修改、添加(text、prop、attr、css)
    jquery_页面加载方式
    jquery_新增元素
    jquery_事件
    Django_POST请求的CSRF验证
    jquery_定位元素
  • 原文地址:https://www.cnblogs.com/gudushishenme/p/3332582.html
Copyright © 2020-2023  润新知