10 泛型库

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

回调

#include <iostream>
#include <vector>

template<typename Iter, typename Callable>
void foreach(Iter current, Iter end, Callable op)
{
  while (current != end)
  {
    op(*current);
    ++current;
  }
}

void func(int i)
{
  std::cout << i << '\n';
}

struct FuncObj {
  void operator()(int i) const
  {
    std::cout << i << '\n';
  }
};

int main()
{
  std::vector<int> primes = { 2, 3, 5, 7, 11, 13, 17, 19 };
  foreach(primes.begin(), primes.end(), func);
  foreach(primes.begin(), primes.end(), &func);
  foreach(primes.begin(), primes.end(), FuncObj());
  foreach(primes.begin(), primes.end(), [] (int i) { std::cout << i << '\n'; });
}

处理成员函数和附加实参

// basics/foreachinvoke.hpp

#include <utility>
#include <functional>
template<typename Iter, typename Callable, typename... Args>
void foreach (Iter current, Iter end, Callable op, const Args&... args)
{
  while (current != end)
  {
    std::invoke(op, args..., *current);
    ++current;
  }
}
#include <iostream>
#include <vector>
#include <string>
#include "foreachinvoke.hpp"

class A {
 public:
  void f(int i) const
  {
    std::cout << i << '\n';
  }
};

int main()
{
  std::vector<int> primes = { 2, 3, 5, 7, 11, 13, 17, 19 };
  foreach(primes.begin(), primes.end(), // 范围内的元素是lambda的第二个参数
    [](std::string const& prefix, int i) {
      std::cout << prefix << i << '\n';
    },
    "value: "); // lambda的第一个参数
  
  A obj;
  foreach(primes.begin(), primes.end(), &A::f, obj);
}

包裹函数调用(Wrapping Function Call)

template<typename Callable, typename... Args>
decltype(auto) call(Callable&& op, Args&&... args)
{
  return std::invoke(std::forward<Callable>(op),
    std::forward<Args>(args)...);
}
template<typename Callable, typename... Args>
decltype(auto) call(Callable&& op, Args&&... args)
{
  decltype(auto) ret{std::invoke(std::forward<Callable>(op),
    std::forward<Args>(args)...)};
  return ret;
}
struct cleanup {
  ~cleanup()
  {
    ... // code to perform on return
  }
} dummy;

return std::invoke(std::forward<Callable>(op), std::forward<Args>(args)...);
template<typename Callable, typename... Args>
decltype(auto) call(Callable&& op, Args&&... args)
{
  if constexpr (std::is_same_v<std::invoke_result_t<Callable, Args...>, void>)
  {
    std::invoke(std::forward<Callable>(op), std::forward<Args>(args)...);
    return;
  }
  else
  {
    decltype(auto) ret{std::invoke(std::forward<Callable>(op),
      std::forward<Args>(args)...)};
    return ret;
  }
}

实现泛型库的其他工具

#include <type_traits>

template<typename T>
class C {
  static_assert(!std::is_same_v<std::remove_cv_t<T>,void>,
    "invalid instantiation of class C for void type");
 public:
  template<typename V>
  void f(V&& v)
  {
    if constexpr(std::is_reference_v<T>)
    {
      ... // 如果T是引用类型
    }
    if constexpr(std::is_convertible_v<std::decay_t<V>,T>)
    {
      ... // 如果V能转换为T
    }
    if constexpr(std::has_virtual_destructor_v<V>)
    {
      ... // 如果V有析构函数
    }
  }
};
std::remove_const_t<const int&> // 生成const int&
std::remove_const_t<std::remove_reference_t<const int&>> // int
std::remove_reference_t<std::remove_const_t<const int&>> // const int
std::decay_t<const int&> // int
make_unsigned_t<int> // unsigned int
make_unsigned_t<const int&> // undefined behavior (hopefully error)
add_rvalue_reference_t<int> // int&&
add_rvalue_reference_t<const int> // const int&&
add_rvalue_reference_t<const int&> // const int&(由于引用折叠,左值引用仍为左值引用)
is_copy_assignable_v<int> // true(一把可以把int赋给int)
is_assignable_v<int, int> // false(不能调用42 = 42)
is_assignable_v<int&, int&> // true
is_swappable_v<int> // true(假设是左值)
is_swappable_v<int&, int&> // true(等价于上一行)
is_swappable_with_v<int, int> // false(考虑值类型)

std::addressof

template<typename T>
void f(T&& x)
{
  auto p = &x; // 如果重载了operator&就可能失败
  auto q = std::addressof(x); // 即使重载了operator&也能工作
  ...
}

std::declval

struct Default { int foo() const { return 1; } };
 
struct NonDefault
{
  NonDefault(const NonDefault&) {}
  int foo() const { return 1; }
};
 
int main()
{
  decltype(Default().foo()) n1 = 1; // n1类型为int
  decltype(NonDefault().foo()) n2 = n1; // 错误:无默认构造函数
  decltype(std::declval<NonDefault>().foo()) n2 = n1; // n2类型为int
}
template<typename T1, typename T2,
  typename RT = std::decay_t<decltype(true ?
    std::declval<T1>() : std::declval<T2>())>>
RT max(T1 a, T2 b)
{
  return b < a ? a : b;
}

完美转发临时对象

template<typename T>
void f(T&& x)
{
  g(std::forward<T>(x)); // 完美转发实参x给g()
}
template<typename T>
void f(T x)
{
  g(doSomething(x));
}
template<typename T>
void f(T x)
{
  auto&& res = doSomething(x);
  doSomethingElse(res);
  set(std::forward<decltype(res)>(res));
}

模板参数为引用的情况

#include <iostream>

template<typename T>
void tmplParamIsReference(T)
{
  std::cout << std::is_reference_v<T> << '\n';
}

int main()
{
  std::cout << std::boolalpha; // 之后打印true将为true而不是1
  int i;
  int& r = i;
  tmplParamIsReference(i); // false
  tmplParamIsReference(r); // false
  tmplParamIsReference<int&>(i); // true
  tmplParamIsReference<int&>(r); // true
}
template<typename T, T Z = T{}>
class RefMem {
 public:
  RefMem() : zero{Z} {}
 private:
  T zero;
};

int null = 0;

int main()
{
  RefMem<int> rm1, rm2;
  rm1 = rm2;       // OK

  RefMem<int&> rm3;    // ERROR: invalid default value for N
  RefMem<int&, 0> rm4;   // ERROR: invalid default value for N

  extern int null;
  RefMem<int&,null> rm5, rm6;
  rm5 = rm6;       // ERROR: operator= is deleted due to reference member
}
#include <vector>
#include <iostream>

template<typename T, int& SZ> // 注意:SZ是引用
class Arr {
 public:
  Arr() : elems(SZ) {}
  void print() const
  {
    for (int i = 0; i < SZ; ++i)
    {
      std::cout << elems[i] << ' ';  
    }
  }
 private:
  std::vector<T> elems;
};

int size = 10;

int main()
{
  Arr<int&, size> y; // compile-time ERROR deep in the code of class std::vector<>
  Arr<int, size> x;  // initializes internal vector with 10 elements
  x.print();    // OK
  size += 100;    // OOPS: modifies SZ in Arr<>
  x.print();    // run-time ERROR: invalid memory access: loops over 120 elements
}
template<typename T, decltype(auto) SZ>
class Arr;
namespace std {
template<typename T1, typename T2>
struct pair {
  T1 first;
  T2 second;
  ...
  // default copy/move constructors are OK even with references:
  pair(pair const&) = default;
  pair(pair&&) = default;
  ...
  // but assignment operator have to be defined to be available with references:
  pair& operator=(pair const& p);
  pair& operator=(pair&& p) noexcept(...);
  ...
};
}
template<typename T>
class optional {
  static_assert(!std::is_reference<T>::value,
    "Invalid instantiation of optional<T> for references");
  ...
};

延迟计算(Defer Evaluation)

template<typename T>
class Cont {
 private:
  T* elems;
 public:
  ...
};
struct Node {
  std::string value;
  Cont<Node> next; // 只有Cont能接受不完整类型时可行
};
template<typename T>
class Cont {
 public:
  std::conditional_t<std::is_move_constructible_v<T>, T&&, T&> foo();
 private:
  T* elems;
};
template<typename T>
class Cont {
 public:
  template<typename U = T>
  std::conditional_t<std::is_move_constructible_v<U>, T&&, T&> foo();
 private:
  T* elems;
};

编写泛型库的考虑事项

上一篇 下一篇

猜你喜欢

热点阅读