/**
* This example shows how to use some of the ref-qualifiers
* in C++11. I honestly wasn't expecting what I found out.
* This example is adapted from yesterday's failed attempts
* at calling methods with ref-qualifiers.
*
* Ref-qualifiers (short for reference qualifiers) are like
* the old C++ const-style qualifiers. For example, everyone
* knows:
*
* class A
* {
* ...
* void doSomething() const; //< Method with const qual.
* };
*
* And those methods cannot be called except for when the
* object is a const object. There is a new adaptation in
* C++11 for references. That's what this blog post is
* trying to illustrate (with a simple example this time).
*/
#include <iostream>
#include <string>
class Grill
{
public:
std::string make;
std::string model;
int btu;
public:
/**
* Delete some of the constructors. We
* don't want to copy, we just want to move.
*/
Grill() = delete;
Grill(Grill const&) = delete;
Grill& operator=(Grill const&) = delete;
/**
* We do allow movement. See prior posts
* about this.
*/
Grill(Grill&& g)
{
this->make = g.make;
this->model = g.model;
this->btu = g.btu;
}
/**
* The only way to construct a grill is to
* give it a make and model OR move it.
*/
Grill(std::string const& makeIn, std::string const& modelIn)
: make(makeIn)
, model(modelIn)
, btu(0)
{
}
/**
* After much frustration, I finally figured out
* how to use this form. The object we call from
* must be an rvalue! Remember- an rvalue is a
* value that cannot be stored at a location in
* memory. If you try to call this with a normal
* object that resides in memory it will not
* compile.
*/
void remoteStart() &&
{
std::cout << this->make
<< " "
<< this->model
<< ", remote start!"
<< std::endl;
}
/**
* This form cannot be called by a const
* object, just by a modifiable lvalue.
* See my blogpost about lvalue vs. rvalues.
*/
void light() &
{
std::cout << this->make
<< " "
<< this->model
<< ", light!"
<< std::endl;
}
void preheat() const&
{
std::cout << this->make
<< " "
<< this->model
<< ", light!"
<< std::endl;
}
};
/**
* The same function from yesterday's blog post. This time
* it's just passing back a copy.
*/
Grill CreateGrill( std::string const& make
, std::string model
, int btu )
{
Grill grill(make, model);
grill.btu = btu;
return grill;
}
/**
* Finally, we get to the main program. This is going to
* show how to use each of the forms above and a bunch of
* forms that won't work.
*/
int main(int argc, char** argv)
{
/**
* The following is obviously broken because of the
* lack of copy constructor.
*/
CreateGrill( "Weber", "Genesis", 3 * 13000 ).remoteStart();
/**
* The following also works because the Grill that
* is constructed isn't bound to a location in
* memory, it is a temporary!
*/
Grill("Weber", "Genesis").remoteStart();
/**
* We create a tangeable Grill (grill1) and we can
* access the regular reference form of the method.
*/
Grill grill1("Charbroil", "3-Burner");
grill1.light();
Grill const& grill2 = grill1;
/**
* This also works because we have a const reference
* to a grill as the object.
*/
grill2.preheat();
#if 0
/**
* This doesn't work because the reference form
* will not take a const ref- it only works with
* modifiable lvalues.
*/
grill2.light();
/**
* This also will not work because the grill
* constructed is an rvalue, and as such this
* value cannot call light(), which has a reference
* qualifier.
*/
Grill("Weber", "Genesis").light();
/**
* This will not work because a non-modifiable
* lvalue (grill2) cannot be used as the object
* when calling a method with an rvalue reference
* base.
*/
grill2.remoteStart();
#endif
}
Monday, May 6, 2013
Eureka! (Ref-Qualifiers Exposed)
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment