美文网首页
第五章:模板的 tricky basics

第五章:模板的 tricky basics

作者: 找不到工作 | 来源:发表于2021-02-03 22:33 被阅读0次

    本章会介绍一些模板的奇技淫巧。

    5.1 用 typename 避免歧义

    typename 可用于表示变量是一个类型。

    template<typename T>
    class MyClass {
      public:
      ...
      void foo() {
        typename T::SubType* ptr;
      }
    };
    

    这里,SubType 是在 T 类型里定义的。如果这里不用 typenameSubType 会被认为是某个非类型的数据(例如某个静态变量,或是枚举类),于是 T::SubType* ptr 就被当作了一个乘法。

    结论是,当某个类型依赖于模板参数时必须用 typename 说明

    例如,如下程序可以打印标准库容器的元素:

    #include <iostream>
    
    
    // print elements of an STL container
    
    template<typename T>
    void printcoll(T const& coll)
    {
      for (typename T::const_iterator iter=coll.begin(); iter != coll.end(); iter++)
      {
        std::cout << *iter << " ";
      }
      std::cout << std::endl;
    }
    

    注意到我们使用了 typename 来指明 T::const_iterator 是一个类型。

    5.2 零值初始化

    对于基础类型如 int, double,没有默认构造函数来用默认值初始化,因此,对于以下模板:

    template<typename T>
    void foo()
    {
      T x;  // x has undefined value is T is built-in type
    }
    

    对于基本类型,这个模板会初始化成未定义的值。自c++11开始,我们可以改进为:

    template<typename T>
    void foo()
    {
      T x{};  // x has zero value is T is built-in type
    }
    

    5.3 使用 this

    如果某个类继承自模板类,x 并不一定等于 this->x

    #include <iostream>
    
    template<typename T>
    class Base {
    public:
      void bar() {std::cout << "Base::bar is called" << std::endl;}
    };
    
    template<typename T>
    class Derived : Base<T> {
    public:
      void foo() {
        this->bar();  // if "this" is not used here, bar() can't be found
      }
    };
    

    结论:基类是模板类时,子类调用基类的方法需要使用 this->Base<T>::

    5.4 template for raw arrays and string literals

    略,不常用

    5.5 类成员模板

    5.5.1 使用 template 避免歧义

    当调用模板类成员时,有时需要指明模板参数。这时候需要使用 template 关键字来确保第一个 < 不被当做“小于”处理。例如:

    template<unsigned long N>
    void printBitset(std::bitset<N> const& bs) {
      std::cout << bs.template to_string<char, std::char_traits<char>, std::allocator<char>>();
    }
    

    这里是调用了 std::bitset 中的模板类成员函数:

        template<class CharT = char,
                 class Traits = char_Traits<CharT>,
                 class Allocator = allocator<CharT>>
          basic_string<CharT, Traits, Allocator>
            to_string(CharT zero = CharT('0'), CharT one = CharT('1')) const;
    

    如果这里不使用 template,编译器会认为 < 是“小于”符号。这个问题仅在它前面的变量依赖于模板参数时存在。例如,这里 ts 变量就是依赖于模板参数 N

    结论:template 关键字仅在模板中使用,且仅在调用依赖模板参数的方法时使用

    5.5.2 Generic Lambdas

    c++14 引入了 generic lambdas,可以作为成员模板的简化。例如以下例子可以计算任意类型的和:

    // c++14 or above
    auto lambda_sum = [](auto x, auto y) {return x + y;};
    

    它是以下例子的简化:

    class MySum {
    public:
      template<typename T1, typename T2>
      auto operator() (T1 x, T2 y) const {
        return x + y;
      }
    };
    

    相关文章

      网友评论

          本文标题:第五章:模板的 tricky basics

          本文链接:https://www.haomeiwen.com/subject/rshzaktx.html