mercredi 29 août 2018

rvalue references, std::reference_wrappers and std::function

I was reading up on r-value references and move semantics. Experimenting this with std::function and std::reference_wrapper unfortunately confused me a bit more.

#include <iostream>
#include <string>
#include <string_view>
#include <functional>

class Greeting {
  std::string g;
  std::function <void(std::string_view)> f;
public:
  Greeting(std::string&& _g, std::function<void(std::string_view)>&& _f)
    : g(std::move(_g)), f(std::move(_f)){};
  void greet() {
    f(g);
  }
};

struct prefix_g {
  std::string g;
public:
  prefix_g(const std::string&& _g) : g(std::move(_g)) {}
  void operator() (std::string_view s) {
    std::cout <<g <<" "<< s << std::endl;
  }
};

int main() {
  prefix_g eng("Hello");

  Greeting g("World",eng);
  Greeting g2("World2",std::ref(eng)); // reference wrapper, special
                                       // forwarding for op ()
  std::string s3("world3"), s4("world3");

  // Greeting g3(std::ref(s3), std::ref(eng)); won't compile; &s3 -> &&s3
  // Greeting g3(s3, eng); won't compile lval to rval
  // Greeting g4(std::move(s4), std::move(eng)); // compiles, output Hello World2 -> World2 as g is moved?

  g.greet(); g2.greet();
  Greeting g4(std::move(s4), std::move(eng));
  g4.greet();

  Greeting g5("world5", std::move(eng)); // UB? move guarantees fn object is
                                         // still valid, ofc, g now gets default
                                         // init to empty
  g5.greet();
  return 0;
}

  1. How is it that r-value references to a std::function actually accepts l-values for eg. in case Greeting g("World",eng), a similar l-value wouldn't be acceptable for any other argument (other than templating the constructor and making a universal reference maybe?) ?
  2. What actually happens when a std::ref is passed to std::function, ref mentions that merely arguments are forwarded. However if I move the function object itself as the commented out g4 is shown I see the output of g2 which uses std::ref to actually see the move in effect, just printing world2

Aucun commentaire:

Enregistrer un commentaire