fork download
  1. #include <iostream>
  2. #include <type_traits>
  3. using namespace std;
  4.  
  5. namespace estd {
  6.  
  7. template<class T, class U = T, std::enable_if_t<
  8. std::is_move_constructible<std::remove_reference_t<T>>::value &&
  9. //std::is_assignable<std::remove_reference_t<T>, std::remove_reference_t<U>&&>::value &&
  10. !std::is_lvalue_reference<U>::value,
  11. int> = 0
  12. >
  13. T exchange(T& obj, U&& new_value) noexcept(
  14. std::is_nothrow_move_constructible<std::remove_reference_t<T>>::value &&
  15. std::is_nothrow_assignable<std::remove_reference_t<T>, std::remove_reference_t<U>&&>::value
  16. )
  17. {
  18. T old_value {std::move(obj)};
  19. obj = std::move(new_value);
  20. return old_value;
  21. }
  22.  
  23. } // namespace estd
  24. void do_stuff() noexcept
  25. { /*...*/ }
  26.  
  27. class Sample
  28. {
  29. std::string mBody;
  30. public:
  31. Sample(const std::string& body = ""): mBody {body} {}
  32.  
  33. Sample(const Sample& s): mBody {s.mBody} {
  34. printf("%s\n", __PRETTY_FUNCTION__); // noexcept
  35. }
  36.  
  37. Sample& operator=(const Sample& s) {
  38. mBody = s.mBody;
  39. printf("%s\n", __PRETTY_FUNCTION__); // noexcept
  40. return *this;
  41. }
  42.  
  43. Sample(Sample&& dying) noexcept(
  44. noexcept(do_stuff()) &&
  45. noexcept(estd::exchange(dying.mBody, {}))
  46. ):
  47. mBody {estd::exchange(dying.mBody, {})}
  48. {
  49. do_stuff(); // noexcept
  50. printf("%s\n", __PRETTY_FUNCTION__); // noexcept
  51. }
  52.  
  53. Sample& operator=(Sample&& dying) noexcept(
  54. noexcept(do_stuff()) &&
  55. noexcept(estd::exchange(dying.mBody, {}))
  56. )
  57. {
  58. mBody = estd::exchange(dying.mBody, {});
  59. do_stuff();
  60. printf("%s\n", __PRETTY_FUNCTION__); // noexcept
  61. return *this;
  62. }
  63.  
  64. std::string body() const noexcept {return mBody;}
  65. };
  66.  
  67. int main()
  68. {
  69. std::cout << std::boolalpha;
  70. Sample rval{"wow such string very content"};
  71. Sample dummy;
  72. std::cout << noexcept( Sample(std::move(rval)) ) << std::endl; // prints true
  73. std::cout << noexcept( dummy = std::move(rval) ) << std::endl; // prints true
  74.  
  75. // The rest only to show that move semantics actually work
  76. Sample f (std::move(rval)); // Calls move ctor
  77. std::cout << rval.body() << std::endl; // prints empty line, empty string moved in rval
  78. std::cout << f.body() << std::endl; // prints wow such string very content
  79.  
  80. // estd::exchange(f, rval); // Fails to compile bc rval is an lvalue reference, template disabled
  81. std::cout << (estd::exchange(f, std::move(rval))).body() << std::endl; // Ok, calls move ctor and move assignment (in estd::exchange) and prints wow such string very content
  82. std::cout << f.body() << std::endl; // empty line, rval (empty) moved in f
  83. std::cout << "end" << std::endl;
  84. }
Success #stdin #stdout 0s 4468KB
stdin
Standard input is empty
stdout
true
true
Sample::Sample(Sample&&)

wow such string very content
Sample::Sample(Sample&&)
Sample& Sample::operator=(Sample&&)
wow such string very content

end