zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C++模版笔记(1)

C++笔记 模版
2023-06-13 09:13:58 时间

本篇介绍

本篇摘录自<<C++ templates>>,记录其中部分内容。

Variadic Templates

操作可变参数

template <typename T>
void func(T arg) {
    std::cout<< arg << std::endl;
}

template <typename T, typename ... Types>
void func(T firstArg, Types... args) {
    func(firstArg);
    func(args...);
}

使用sizeof...(args)即可获取到变量个数。

在c++ 17上可以按照如下方式操作可变入参:

template <typename... T>
auto sum(T... s) {
    return (... + s);  // ((s1 +s2) + s3)
}

具体格式如下:

image.png

std::enable_if

利用SFINE性质,也就是只要可以匹配成功,即使某些场景匹配失败也不是错误。

template<bool B, class T = void>
struct enable_if {};
 
template<class T>
struct enable_if<true, T> { typedef T type; };

using 在模版中的使用

using 有给类型重命名的作用,也有继承父类所有构造函数的作用,比如:

struct Base {
    int val;
    Base() { val = 0;}
    Base(int m):val(m) {
    }
};

struct Derived : public Base {
    using Base::Base;
};

通过using 就可以一下子使用到父类的所有构造函数。

也可以通过模版支持获取所有类的操作符重载方法:

class Customer
{
  private:
    std::string name;
  public:
    Customer(std::string const& n) : name(n) { }
    std::string getName() const { return name; }
};

struct CustomerEq {
      bool operator() (Customer const& c1, Customer const& c2) const {
        return c1.getName() == c2.getName();
      }
};
  struct CustomerHash {
      std::size_t operator() (Customer const& c) const {
        return std::hash<std::string>()(c.getName());
      }
};

template<typename... Bases>
struct Overloader : Bases...
{
    using Bases::operator()...;
};

using CustomerOP = Overloader<CustomerHash,CustomerEq>;

std::unordered_set<Customer,CustomerOP,CustomerOP> col;

typename

在模版使用过程中,typename 和class 是等同的,不过typename还有一层含义,就是修饰的参数一定是类型。

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

这儿的 T::SubType 是类型。

模版友元

如果希望支持模版不同特化之间可以访问私有数据,那么就可以设置模版特化是友元的。

template <typename T> 
class Stack {
template <typename> friend class Stack;
};

变量模版

可以用变量来表示类模版的成员值:

 namespace std {
     template<typename T> constexpr bool is_const_v = is_const<T>::value;
}

这样通过is_const_v<T> 就可以表示 is_const<T>::value

模版模版参数

如果模版参数中的类型本身也是一个模版,比如还是Stack, Stack<int, std::vector<int>> 可以看到第一个模版参数是int,第二个模版参数还是一个int,这时候就是模版的模版参数了,要声明这种场景,方法如下:

template<typename T,
          template<typename Elem> class Cont = std::deque>

在模版里再写一下 template<typename Elem>,就表明第二个参数也是模版。 这时候完整的Stack 如下:

#include <deque>
#include <cassert>
#include <memory>
template<typename T,
           template<typename Elem,
                    typename = std::allocator<Elem>>
            class Cont = std::deque>
 class Stack {
  private:
    Cont<T> elems;
  public:
    void push(T const&);
    void pop();
    T const& top() const;
    bool empty() const {
    return elems.empty();
}
// assign stack of elements of type T2 template<typename T2,
 template<typename Elem2,
                      typename = std::allocator<Elem2>
                     >class Cont2>
    Stack<T,Cont>& operator= (Stack<T2,Cont2> const&);
// to get access to private members of any Stack with elements of type T2: template<typename, template<typename, typename>class> friend class Stack;
};

template<typename T, template<typename,typename> class Cont>
void Stack<T,Cont>::push (T const& elem)
{
elems.push_back(elem); // append copy of passed elem 
}

template<typename T, template<typename,typename> class Cont>
void Stack<T,Cont>::pop ()
{
    assert(!elems.empty());
    elems.pop_back();
// remove last element
}
template<typename T, template<typename,typename> class Cont>
T const& Stack<T,Cont>::top () const
{
    assert(!elems.empty());
return elems.back(); // return copy of last element 
}

template<typename T, template<typename,typename> class Cont>
 template<typename T2, template<typename,typename> class Cont2>
Stack<T,Cont>&
Stack<T,Cont>::operator= (Stack<T2,Cont2> const& op2)
{
elems.clear();
elems.insert(elems.begin(),
             op2.elems.begin(),
             op2.elems.end());
return *this;
// remove existing elements // insert at the beginning
// all elements from op2
}