06 移动语义与 enable_if

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

完美转发(Perfect Forwarding)

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

// 用多个重载转发给对应版本比较繁琐
void g(int& x)
{
  f(x);
}

void g(const int& x)
{
  f(x);
}

void g(int&& x)
{
  f(std::move(x));
}

// 同样可以用一个模板来替代上述功能
template<typename T>
void h(T&& x)
{
  f(std::forward<T>(x)); // 注意std::forward的模板参数是T
}

int main()
{
  int a = 1;
  const int b = 1;

  g(a); h(a); // 11
  g(b); h(b); // 22
  g(std::move(a)); h(std::move(a)); // 33
  g(1); h(1); // 33
}
template<typename... Ts>
void f(Ts&&... args)
{
  g(std::forward<Ts>(args)...); // 把任意数量的实参转发给g
}
auto f = [](auto&& x) { return g(std::forward<decltype(x)>(x)); };

// 转发任意数量实参
auto f = [](auto&&... args) {
  return g(std::forward<decltype(args)>(args)...);
};
template<typename T>
void f(T x)
{
  auto&& res = doSomething(x);
  doSomethingElse(res);
  set(std::forward<decltype(res)>(res));
}

特殊成员函数模板

class Person {
 public:
  explicit Person(const std::string& n) : name(n) {} // 拷贝初始化函数
  explicit Person(std::string&& n) : name(std::move(n)) {} // 移动初始化函数
  Person(const Person& p) : name(p.name) {} // 拷贝构造函数
  Person(Person&& p) : name(std::move(p.name)) {} // 移动构造函数
 private:
  std::string name;
};

int main()
{
  std::string s = "sname";
  Person p1(s); // 调用拷贝初始化函数
  Person p2("tmp"); // 调用移动初始化函数
  Person p3(p1); // 调用拷贝构造函数
  Person p4(std::move(p1)); // 调用移动构造函数
}
class Person {
 public:
  template<typename STR> // 完美转发构造函数
  explicit Person(STR&& n) : name(std::forward<STR>(n)) {}
  Person(const Person& p) : name(p.name) {} // 拷贝构造函数
  Person(Person&& p) : name(std::move(p.name)) {} // 移动构造函数
 private:
  std::string name;
};
std::string s = "sname";
Person p1(s); // 调用完美转发构造函数
Person p2("tmp"); // 调用完美转发构造函数
Person p4(std::move(p1)); // 调用移动构造函数
Person p3(p1); // 错误
const Person p2c("ctmp"); // 调用完美转发构造函数
Person p3c(p2c); // 调用拷贝构造函数
// 对于Person p1的匹配
template<typename STR>
Person(STR&&)
// 优于
Person(const Person&)
Person(Person&);

使用enable_if禁用成员模板

#include <type_traits>

template<typename T>
typename std::enable_if<(sizeof(T) > 4)>::type
f() {}
void f() {}
template<typename T>
std::enable_if<(sizeof(T) > 4), T>::type f()
{
  return T();
}
template<typename T>
std::enable_if_t<(sizeof(T) > 4)>
f() {}
template<typename T, typename = std::enable_if_t<(sizeof(T) > 4)>>
void f() {}
template<typename T, typename = void>
void f() {}
template<typename T>
using EnableIfSizeGreater4 = std::enable_if_t<(sizeof(T) > 4)>;

template<typename T, typename = EnableIfSizeGreater4<T>>
void f() {}

使用enable_if解决完美转发构造函数的优先匹配问题

template<typename STR,
  typename = std::enable_if_t<std::is_convertible<STR, std::string>::value>>
explicit Person(STR&& n) : name(std::forward<STR>(n)) {}
template<typename STR, typename = void>
explicit Person(STR&& n) : name(std::forward<STR>(n)) {}
#include <iostream>
#include <string>
#include <type_traits>

template<typename T>
using EnableIfString = std::enable_if_t<std::is_convertible_v<T, std::string>>;

class Person {
 public:
  template<typename STR, typename = EnableIfString<STR>>
  explicit Person(STR&& n) : name(std::forward<STR>(n)) {}
  Person(const Person& p) : name(p.name) {}
  Person(Person&& p) : name(std::move(p.name)) {}
 private:
  std::string name;
};

int main()
{
  std::string s = "sname";
  Person p1(s); // 调用完美转发构造函数
  Person p2("tmp"); // 调用完美转发构造函数
  Person p3(p1); // 调用拷贝构造函数
  Person p4(std::move(p1)); // 调用移动构造函数
}
template<typename T>
using EnableIfString = std::enable_if_t<std::is_constructible_v<std::string, T>>;

模板与预定义的特殊成员函数

class C {
 public:
  template<typename T>
  C(const T&) {}
};

C x;
C y{x}; // 仍然使用预定义合成的拷贝构造函数,上面的模板被忽略
class C {
 public:
  C(const volatile C&) = delete; // 显式声明将阻止默认合成拷贝构造函数
  template<typename T>
  C(const T&) {}
};

C x;
C y{x}; // 使用模板
template<typename T>
class C {
 public:
  C(const volatile C&) = delete;
  template<typename U, typename = std::enable_if_t<!std::is_integral_v<U>>>
  C(const C<U>&) {}
};

使用concepts替代enable_if以简化表达式

template<typename STR,
  typename = std::enable_if_t<std::is_convertible_v<STR, std::string>>>
explicit Person(STR&& n) : name(std::forward<STR>(n)) {}
template<typename STR>
requires std::is_convertible_v<STR, std::string>
explicit Person(STR&& n) : name(std::forward<STR>(n)) {}
template<typename T>
concept ConvertibleToString = std::is_convertible_v<T,std::string>;
template<typename STR>
requires ConvertibleToString<STR>
explicit Person(STR&& n) : name(std::forward<STR>(n)) {}
template<ConvertibleToString STR>
explicit Person(STR&& n) : name(std::forward<STR>(n)) {}
上一篇下一篇

猜你喜欢

热点阅读