15 特化与重载

2021-05-30  本文已影响0人  奇点创客

重载模板以适用不同的情况

template<typename T>
class Array {
 public:
  Array(const Array<T>&);
  Array<T>& operator=(const Array<T>&);
  void exchangeWith(Array<T>* b)
  {
    T* tmp = data;
    data = b->data;
    b->data = tmp;
  }
  T& operator[](std::size_t k)
  {
    return data[k];
  }
 private:
  T* data;
};

template<typename T> inline
void exchange(T* a, T* b)
{
  T tmp(*a);
  *a = *b;
  *b = tmp;
}
template<typename T> inline
void quick_exchange(T* a, T* b) // (1)
{
  T tmp(*a);
  *a = *b;
  *b = tmp;
}

template<typename T> inline
void quick_exchange(Array<T>* a, Array<T>* b) // (2)
{
  a->exchange_with(b);
}

void demo(Array<int>* p1, Array<int>* p2)
{
  int x = 42, y = -7;
  quick_exchange(&x, &y); // 使用(1)
  quick_exchange(p1, p2); // 使用(2):重载会优先选择更加特殊的模板
}
struct S {
  int x;
} s1, s2;

void distinguish(Array<int> a1, Array<int> a2)
{
  a1[0] = 1;
  a2[0] = 2;
  s1.x = 3;
  s2.x = 4;
  int* p = &a1[0]; // p和a1->data指向同一处,此处存储的值为1
  int* q = &s1.x; // q指向s1.x,s1.x的值为3
  quick_exchange(&a1, &a2); // a1->data和a2->data交换了,现在换a2->data和p指向1
  quick_exchange(&s1, &s2); // s1和s2的值交换了,s1.x现在为4,所以*q为4
}
int main()
{
  int* a = new int[3];
  a[0] = 1;
  int* p = &a[0]; // 把a现在的地址赋值给p,之后a指向哪都不会改变p

  int* b = new int[3];
  b[0] = 2;
  int* q = b;
  b = a; // 此时abp都指向一处
  a = q; // a指向了原来b的那处,bp指向一处
  std::cout << a[0] <<  b[0] << *p; // 211
}
// 更简单的例子
int main()
{
  int i = 1, j = 2;
  int* p = &i; // 把i的地址赋值给p
  int* q = p; // 把p的值,即i的地址赋值给q
  p = &j; // p的值改为j的地址,但q的值仍为i的地址
  std::cout << *q; // 1
}
template<typename T>
void quick_exchange(T* a, T* b)
{
  T tmp(*a);
  *a = *b;
  *b = tmp;
}

template<typename T>
void quick_exchange(Array<T>* a, Array<T>* b)
{
  T* p = &(*a)[0];
  T* q = &(*b)[0];
  for (std::size_t k = a->size(); k-- != 0; )
  {
    quick_exchange(p++, q++); // 如果T也是Array则递归调用此模板
  }
}

签名(Signature)

template<typename T1, typename T2>
void f(T1, T2);

template<typename T1, typename T2>
void f(T2, T1);

template<typename T>
long g(T);

template<typename T>
char g(T);
#include <iostream>

template<typename T1, typename T2>
void f(T1, T2) {}

template<typename T1, typename T2>
void f(T2, T1) {}

int main()
{
  f<char, char>('a', 'b'); // 二义性错误
}
// Translation unit 1:
#include <iostream>

template<typename T1, typename T2>
void f(T1, T2)
{
  std::cout << 1;
}

void g()
{
  f<char, char>('a', 'b');
}

// Translation unit 2:
#include <iostream>

template<typename T1, typename T2>
void f(T2, T1)
{
  std::cout << 2;
}

extern void g(); // defined in translation unit 1

int main()
{
  f<char, char>('a', 'b'); // 2
  g(); // 1
}

函数模板的偏序(Partial Ordering)规则

#include <iostream>

template<typename T>
void f(T)
{
  std::cout << 1;
}

template<typename T>
void f(T*)
{
  std::cout << 2;
}

int main()
{
  f<int*>((int*)nullptr); // 1:重载解析
  f<int>((int*)nullptr); // 2:重载解析
  f(0); // 1:0被推断为int,无重载解析,匹配第一个模板
  f(nullptr); // 1
  f((int*)nullptr); // 2:重载解析,第二个更特殊
}
template<typename T>
void f(T*, const T* = nullptr, ...);

template<typename T>
void f(const T*, T*, T* = nullptr);

void example(int* p)
{
  f(p, p); // 错误:二义性调用,两个模板没有偏序关系,一样特殊
}

普通函数会被重载优先考虑

template<typename T>
void f(T)
{
  std::cout << 1;
}

void f(int&)
{
  std::cout << 2;
}

int main()
{
  int x = 0;
  f(x); // 2
}
template<typename T>
void f(T)
{
  std::cout << 1;
}

void f(const int&)
{
  std::cout << 2;
}

int main()
{
  int x = 0;
  f(x); // 1
  const int y = 0;
  f(y); // 2
}
class C {
 public:
  C() = default;
  C(const C&) { std::cout << 1; }
  C(C&&) { std::cout << 2; }
  template<typename T>
  C(T&&) { std::cout << 3; }
};

int main()
{
  C x;
  C x2{x}; // 3:对于non-const,成员模板是比拷贝构造函数更好的匹配
  C x3{std::move(x)}; // 2
  const C c;
  C x4{c}; // 1
  C x5{std::move(c)}; // 3:对于const C&&(尽管不常见),成员模板比移动构造函数更好
}

可变参数函数模板的重载

#include <iostream>

template<typename T>
void f(T*)
{
  std::cout << 1;
}

template<typename... Ts>
void f(Ts...)
{
  std::cout << 2;
}

template<typename... Ts>
void f(Ts*...)
{
  std::cout << 3;
}

int main()
{
  f(0, 0.0); // 2
  f((int*)nullptr, (double*)nullptr); // 3
  f((int*)nullptr); // 1
}
#include <iostream>

template<typename... Ts>
class Tuple {};

template<typename T>
void f(Tuple<T*>)
{
  std::cout << 1;
}

template<typename... Ts>
void f(Tuple<Ts...>)
{
  std::cout << 2;
}

template<typename... Ts>
void f(Tuple<Ts*...>)
{
  std::cout << 3;
}

int main()
{
  f(Tuple<int, double>()); // 2
  f(Tuple<int*, double*>()); // 3
  f(Tuple<int*>()); // 1
}

函数模板全特化

template<typename T>
int f(T) // (1)
{
  return 1;
}

template<typename T>
int f(T*) // (2)
{
  return 2;
}

template<>
int f(int) // OK:(1)的特化
{
  return 3;
}

template<>
int f(int*) // OK:(2)的特化
{
  return 4;
}
template<typename T>
int f(T, T x = 42)
{
  return x;
}

template<>
int f(int, int = 35) // 错误
{
  return 0;
}

template<typename T>
int g(T, T x = 42)
{
  return x;
}

template<>
int g(int, int y)
{
  return y/2;
}

int main()
{
  std::cout << g(0) << std::endl; // 21
}
#ifndef TEMPLATE_G_HPP
#define TEMPLATE_G_HPP

// 模板定义应放在头文件中
template<typename T>
int g(T, T x = 42)
{
  return x;
}

// 特化声明会阻止模板实例化
// 为避免重定义错误不在此定义
template<>
int g(int, int y);

#endif // TEMPLATE_G_HPP

// 实现文件
#include "template_g.hpp"
template<>
int g(int, int y)
{
  return y/2;
}

类模板全特化

template<typename T>
class Types {
 public:
  using I = int;
};

template<typename T, typename U = typename Types<T>::I>
class X; // (1)

template<>
class X<void> { // (2)使用默认实参:X<void, int>
 public:
  void f();
};

template<> class X<char, char>; // (3)

template<> class X<char, 0>; // 错误:0不能替换U

int main()
{
  X<int>* pi; // OK:使用(1),不需要定义
  X<int> e1; // 错误:使用(1)但没有定义
  X<void>* pv; // OK:使用(2)
  X<void, int> sv; // OK:使用(2)
  X<void, char> e2; // 错误:使用(1)但没有定义
  X<char, char> e3; // 错误:使用(3)但没有定义
}

template<>
class X<char, char> {} // (3)的定义
template<typename T>
class X; // 必须有此前置声明才能特化

template<>
class X<char**> {
 public:
  void print() const;
};

// 下面的定义不能使用template<>前缀
void X<char**>::print() const
{
  std::cout << "pointer to pointer to char\n";
}

// 另一个例子
template<typename T>
class A {
 public:
  template<typename U>
  class B {};
};

template<>
class A<void> {
  // 下面的嵌套类和上面定义的泛型模板之间并不存在联系
  template<typename U>
  class B {
   private:
    static int i;
  };
};

// 下面的定义不能使用template<>前缀
template<typename U>
int A<void>::B<U>::i = 1;
template<typename T>
class X {};

X<double> x; // 产生一个X<double>实例化体

template<>
class X<double>; // 错误:X<double>已经被实例化了
// Translation unit 1:
template<typename T>
class X {
 public:
  enum { max = 10; };
};

char buffer[X<void>::max]; // 使用的max是10

extern void f(char*);

int main()
{
  f(buffer);
}

// Translation unit 2:
template<typename T>
class X;

template<>
class X<void> {
 public:
  enum { max = 100; };
};

void f(const char* buf)
{
  // 可能与原先定义的数组大小不匹配
  for (int i = 0; i < X<void>::max; ++i)
  {
    buf[i] = '\0';
  }
}

成员全特化

template<typename T>
class A {
 public:
  template<typename U>
  class B {
   private:
    static int x;
  };

  static int y;

  void print() const
  {
    std::cout << "generic";
  }
};

template<typename T>
int A<T>::y = 6;

template<typename T>
  template<typename U>
int A<T>::B<U>::x = 7;

// A<bool>的特化,对特化整个类模板可以完全改变类的成员
template<>
class A<bool> {
 public:
  template<typename U>
  class B {
   private:
    static int x;
  };

  void print() const {}
};

// 由于A<bool>中的B也是类模板,所以也可以特化
template<> // 特化的普通成员不需要加template<>前缀,但B是模板
class A<bool>::B<wchar_t> {
 public:
  enum { x = 2 };
};

// 下面是A<void>成员的特化,A<void>其他成员将来自原模板
// 成员特化后就不能再特化整个A<void>
template<>
int A<void>::y = 12;

template<>
void A<void>::print() const
{
  std::cout << "A<void>";
}
// template<> class A<void> {}; // 错误:不能再特化A<void>

// 特化A<wchar_t>::B
template<>
  template<typename U>
class A<wchar_t>::B {
 public:
  static long x; // 成员类型发生了改变
};

template<>
  template<typename X>
long A<wchar_t>::B<X>::x;

// 特化A<char>::B<wchar_t>
template<> // A<char>没被特化,所以比特化A<bool>::B<wchar_t>多一个前缀
  template<>
class A<char>::B<wchar_t> {
 public:
  enum { x = 1 };
};
class A {
  void f();
};

void A::f(); // 错误
template<typename T>
class A {
 public:
  template<typename U>
  class B {
   private:
    static int x;
  };

  static int y;

  void print() const
  {
    std::cout << "generic";
  }
};

template<>
int A<void>::y;

template<>
void A<void>::print() const;
class X {
 public:
  X() = default;
  X(const X&) = delete;
};

template<typename T>
class Y {
 private:
  static T i;
};

// 下面只是一个声明
template<>
X Y<X>::i;
// 下面是定义(C++11前不存在定义的方法)
template<>
X Y<X>::i{};
// C++11前
template<>
X Y<X>::i = X(); // 但这不可行,因为拷贝构造函数被删除了
// 但C++17引入了copy-elision规则又使得这个方法可行

类模板偏特化

template<typename T>
class X {}; // 原始模板

template<typename T>
class X<const T> {}; // T为const的情况

template<typename T>
class X<T*> {}; // T为指针的情况

template<typename T, int N> // 参数个数可以和原始模板不一致
class X<T[N]> {}; // T为数组的情况

template<typename A>
class X<void* A::*> {}; // T为成员指针且成员返回类型为void的情况

template<typename T, typename A>
class X<T* A::*> {}; // T为成员指针的情况(如果为void则调用上一个偏特化)

template<int I, int N>
class S {};

template<int N>
class S<2, N> {}; // I为2的情况

template<typename... Ts>
class Tuple {}; // 原始模板

template<typename T>
class Tuple<T> {}; // tuple只有单个元素的情况

template<typename T1, typename T2, typename... Ts>
class Tuple<T1, T2, Ts...> {}; // tuple有两个以上元素的情况
template<typename T>
class X {};

template<>
class X<void*> {}; // 加上此全特化以防X<void*>产生无限递归

template<typename T>
class X<T*> {
 public:
  X<void*> x; // X<void*>中又包含X<void*>,将产生无限递归
};
template<typename T, int I = 3>
class X {}; // 原始模板

template<typename T>
class X<int, T> {}; // 错误:参数类型不匹配

template<typename T = int>
class X<T, 10> {}; // 错误:不能有默认实参(可以用原始模板的默认实参)

template<int I>
class X<int, I*2> {}; // 错误:不能有非类型表达式

template<typename U, int K>
class X<U, K> {}; // 错误:与原始模板相同

template<typename... Ts>
class Tuple {}; 

template<typename T, typename... Ts>
class Tuple<Ts..., T> {}; // 错误:包扩展必须在实参列表末尾

template<typename T, typename... Ts>
class Tuple<Tuple<Ts...>, T> {}; // OK:包扩展在嵌套模板实参列表末尾
template<typename T>
class X {};

template<typename T>
class X<const T> {};

template<typename T, int N>
class X<T[N]> {};

X<const int[3]> x; // 错误:两个偏特化匹配程度相同
template<typename T>
class X {};

template<typename T>
class X<T*> {
 public:
  void f();
};

template<typename T>
void X<T*>::f() {}

变量模板全特化

template<typename T>
constexpr std::size_t X = sizeof(T);

template<>
constexpr std::size_t X<void> = 0;
template<typename T>
typename T::iterator null_iterator; // 一个空迭代器(但不是nullptr)

template<>
int* null_iterator<std::vector<int>> = nullptr; // 允许int*不匹配T::iterator

auto p = null_iterator<std::vector<int>>; // int* p = nullptr
auto q = null_iterator<std::deque<int>>; // std::deque<int>::iterator q = 空迭代器

变量模板偏特化

template<typename T>
constexpr std::size_t X = sizeof(T);

template<typename T>
constexpr std::size_t X<T&> = sizeof(void*);
template<typename T>
typename T::iterator null_iterator;

template<typename T, std::size_t N>
T* null_iterator<T[N]> = nullptr;

auto p = null_iterator<int[3]>; // int* p = nullptr
auto q = null_iterator<std::deque<int>>; // std::deque<int>::iterator q = 空迭代器
上一篇 下一篇

猜你喜欢

热点阅读