Skip to the content.

移动语义(Move Semantics)

#include <cassert>
#include <string>
#include <utility>
#include <vector>

namespace jc {

struct A {
  A() : data(new std::string) {}
  A(const A& rhs) : data(new std::string{*rhs.data}) {}
  A(A&& rhs) noexcept : data(rhs.data) { rhs.data = nullptr; }
  ~A() { delete data; }

  std::string* data = nullptr;
};

}  // namespace jc

int main() {
  std::vector<jc::A> v;
  v.emplace_back(jc::A{});  // 调用默认构造函数、移动构造函数、析构函数
  jc::A a;
  v.emplace_back(a);  // 调用拷贝构造函数
  assert(a.data);
  v.emplace_back(std::move(a));  // 调用移动构造函数
  assert(!a.data);
}
#include <cassert>
#include <string>
#include <type_traits>
#include <utility>

namespace jc {

template <typename T>
constexpr std::remove_reference_t<T>&& move(T&& x) noexcept {
  return static_cast<std::remove_reference_t<T>&&>(x);
}

constexpr int f(const std::string&) { return 1; }
constexpr int f(std::string&&) { return 2; }

}  // namespace jc

int main() {
  std::string s;
  static_assert(jc::f(s) == 1);
  assert(jc::f(std::string{}) == 2);
  static_assert(jc::f(static_cast<std::string&&>(s)) == 2);
  static_assert(jc::f(jc::move(s)) == 2);
  static_assert(jc::f(std::move(s)) == 2);
}

完美转发(Perfect Forwarding)

#include <cassert>
#include <string>
#include <utility>

namespace jc {

constexpr int f(const std::string&) { return 1; }
constexpr int f(std::string&&) { return 2; }
constexpr int g(std::string&& s) { return f(s); }

void test() {
  std::string s;
  assert(f(std::string{}) == 2);
  assert(g(std::string{}) == 1);
  static_assert(f(std::move(s)) == 2);
  static_assert(g(std::move(s)) == 1);
}

}  // namespace jc

int main() { jc::test(); }
#include <cassert>
#include <string>
#include <utility>

namespace jc {

constexpr int f(std::string&) { return 1; }
constexpr int f(const std::string&) { return 2; }
constexpr int f(std::string&&) { return 3; }
constexpr int g(std::string& s) { return f(s); }
constexpr int g(const std::string& s) { return f(s); }
constexpr int g(std::string&& s) { return f(std::move(s)); }

void test() {
  std::string s;
  const std::string& s2 = s;
  static_assert(g(s) == 1);
  assert(g(s2) == 2);
  static_assert(g(std::move(s)) == 3);
  assert(g(std::string{}) == 3);
}

}  // namespace jc

int main() { jc::test(); }
#include <cassert>
#include <string>
#include <type_traits>

namespace jc {

template <typename T>
constexpr T&& forward(std::remove_reference_t<T>& t) noexcept {
  return static_cast<T&&>(t);
}

constexpr int f(std::string&) { return 1; }
constexpr int f(const std::string&) { return 2; }
constexpr int f(std::string&&) { return 3; }

template <typename T>
constexpr int g(T&& s) {
  return f(jc::forward<T>(s));  // 等价于 std::forward
}

void test() {
  std::string s;
  const std::string& s2 = s;
  static_assert(g(s) == 1);             // T = T&& = std::string&
  assert(g(s2) == 2);                   // T = T&& = const std::string&
  static_assert(g(std::move(s)) == 3);  // T = std::string, T&& = std::string&&
  assert(g(std::string{}) == 3);        // T = T&& = std::string&
  assert(g("downdemo") == 3);           // T = T&& = const char (&)[9]
}

}  // namespace jc

int main() { jc::test(); }
#include <iostream>
#include <string>
#include <type_traits>
#include <utility>

namespace jc {

template <typename F, typename... Args>
constexpr void constexpr_for(F&& f, Args&&... args) {
  (std::invoke(std::forward<F>(f), std::forward<Args>(args)), ...);
}

template <typename... Args>
void print(Args&&... args) {
  constexpr_for([](const auto& x) { std::cout << x << std::endl; },
                std::forward<Args>(args)...);
}

}  // namespace jc

int main() { jc::print(3.14, 42, std::string{"hello"}, "world"); }
#include <iostream>
#include <string>
#include <type_traits>
#include <utility>

namespace jc {

constexpr auto constexpr_for = [](auto&& f, auto&&... args) {
  (std::invoke(std::forward<decltype(f)>(f),
               std::forward<decltype(args)>(args)),
   ...);
};

auto print = [](auto&&... args) {
  constexpr_for([](const auto& x) { std::cout << x << std::endl; },
                std::forward<decltype(args)>(args)...);
};

}  // namespace jc

int main() { jc::print(3.14, 42, std::string{"hello"}, "world"); }
#include <iostream>
#include <string>
#include <type_traits>
#include <utility>

namespace jc {

constexpr auto constexpr_for =
    []<typename F, typename... Args>(F&& f, Args&&... args) {
  (std::invoke(std::forward<F>(f), std::forward<Args>(args)), ...);
};

auto print = []<typename... Args>(Args&& ... args) {
  constexpr_for([](const auto& x) { std::cout << x << std::endl; },
                std::forward<Args>(args)...);
};

}  // namespace jc

int main() { jc::print(3.14, 42, std::string{"hello"}, "world"); }
#include <iostream>
#include <string>
#include <type_traits>
#include <utility>

namespace jc {

template <typename... Args>
void print(Args&&... args) {
  [... args = std::forward<Args>(args)]<typename F>(F&& f) {
    (std::invoke(std::forward<F>(f), args), ...);
  }([](const auto& x) { std::cout << x << std::endl; });
}

}  // namespace jc

int main() { jc::print(3.14, 42, std::string{"hello"}, "world"); }

构造函数模板

#include <string>
#include <utility>

namespace jc {

struct A {
  template <typename T>
  explicit A(T&& t) : s(std::forward<T>(t)) {}

  A(const A& rhs) : s(rhs.s) {}
  A(A&& rhs) noexcept : s(std::move(rhs.s)) {}

  std::string s;
};

}  // namespace jc

int main() {
  const jc::A a{"downdemo"};
  jc::A b{a};  // OK,匹配拷贝构造函数
  //   jc::A c{b};  // 错误,匹配模板构造函数
}
#include <string>
#include <type_traits>
#include <utility>

namespace jc {

struct A {
  template <typename T,  // 要求 T 能转为 std::string
            typename = std::enable_if_t<std::is_convertible_v<T, std::string>>>
  explicit A(T&& t) : s(std::forward<T>(t)) {}

  A(const A& rhs) : s(rhs.s) {}
  A(A&& rhs) noexcept : s(std::move(rhs.s)) {}

  std::string s;
};

}  // namespace jc

int main() {
  const jc::A a{"downdemo"};
  jc::A b{a};  // OK,匹配拷贝构造函数
  jc::A c{b};  // OK,匹配拷贝构造函数
}
#include <concepts>
#include <string>
#include <utility>

namespace jc {

struct A {
  template <typename T>
    requires std::convertible_to<T, std::string>
  explicit A(T&& t) : s(std::forward<T>(t)) {}

  A(const A& rhs) : s(rhs.s) {}
  A(A&& rhs) noexcept : s(std::move(rhs.s)) {}

  std::string s;
};

}  // namespace jc

int main() {
  const jc::A a{"downdemo"};
  jc::A b{a};  // OK,匹配拷贝构造函数
  jc::A c{b};  // OK,匹配拷贝构造函数
}