Since I'm a beginner in c++, some questions don't quite understand. This question came across by accident while I was reading C++ primer 5th.
I have a Cat class with 3 different constructors(named by Constructor 1, Constructor 2, Constructor 3):
class Cat {
friend class Cats;
private:
std::string name;
public:
Cat() = default;
// Constructor 1
Cat(std::string n): name(n) {
std::printf("Call: Cat(std::string n)\n");
}
// Constructor 2
Cat(std::string& n): name(n) {
std::printf("Call: Cat(std::string& n)\n");
}
// Constructor 3
Cat(const std::string& n): name(n) {
std::printf("Call: Cat(const std::string &n)\n");
}
};
And I want to instantiate the class in two different ways:
class C7T17_Main {
public:
void run() {
// Instantiation 1
Cat cat(std::string("Cathy"));
// Instantiation 2
std::string s("Mike");
Cat cat2(s);
}
};
Then the problem comes:
For
Constructor 1:Instantiation 1andInstantiation 2both work well
For
Constructor 2:Instantiation 1raises an error. The compiler complains that 'Candidate constructor not viable: expects an lvalue for 1st argument'Instantiation 2works normally.
For
Constructor 3:Instantiation 1andInstantiation 2both work well
My guess is:
Instantiation 1does not actually create a variable, but a temporary value for initializing cat, so it is not suitable as a reference parameter.For
constructor 3, the const reference parameter represents a constant that can accept a temporary value for initialization
Looking forward to your help. :)
It's pretty simple:
Yes, it creates a prvalue, and it can be passed by reference like this:
ctor 4 only accepts temporaries (rvalues) by reference.
Yes, it can bind to all the values as I mentioned previously.
This is the expected behavior.
Important Note:
Function parameters that are of type rvalue reference are lvalues themselves. So in the above code,
nis a variable and it's an lvalue. Thus it has an identity and can not be moved from (you need to usestd::movein order to make it movable).Extra note:
You can even pass an lvalue to a function that only accepts rvalues like this:
std::moveperforms a simple cast. It casts an lvalue to an xvalue so it becomes usable by a function that only accepts an rvalue.Value Category in C++11
Take a look at this:
Explanation for the above image
Read more about this topic at value categories.