I'm trying to figure out how to write "fully generic function" for sqr operation (it's actually can be multiply, division, add, does not really matter).
Consider the following code
#include <iostream>
struct A
{
int val = 2;
A() = default;
A(const A&) = delete; // To make sure we do not copy anything
A(A&& a) = delete; // To make sure we do not move anything
auto operator=(auto) = delete; // To make sure we do not assign anything
// This is important part, we do not want to create a new object on each multiplication.
// We want just to update the old one.
A& operator*(const A& a)
{
val *= a.val;
return *this;
}
};
// Just for easy printing (you can ignore it).
std::ostream &operator<<(std::ostream &os, const A& a) {
return os << a.val;
}
// Here auto&& represents forwarding reference and should automatically understand whether input r or l value.
auto&& sqr(auto&& val)
{
return val * val;
}
int main()
{
A a;
std::cout << sqr(a) << "\n"; // OK
std::cout << sqr(A()) << "\n"; // OK
std::cout << sqr(1) << "\n"; // Wrong, ref to local returned
int i = 2;
std::cout << sqr(i) << "\n"; // Wrong, ref to local returned
}
sqr function here is meant to be sort of generic stuff, it should handle all possible situations (r-values, l-values) and for object a it's actually does, but not for i. I can't get why it's trying to return reference instead of copy. Could anyone please shed some light on the situation? Is there any way I can accomplish this task easily (with one template function ideally)? I can use c++ 20 standard if necessary.
auto&& sqr(auto&& val)
{
return val * val;
}
sqr above always returns a reference. But returning a reference to a local is always wrong. Let the return-type deduce to a non-reference by using auto instead.
constexpr // May be constexpr for some types
auto sqr(auto&& x) // return type is non-reference or trailing
noexcept(noexcept(x*x)) // propagate noexcept
-> decltype(x*x) // enable SFINAE
{ return x * x; }
Related
Basically, I'm trying to learn about C++ 17, and I found as_const.
What's the difference when we use:
MyType t;
auto& p = as_const(t);
instead of:
MyType t;
const auto& p = t;
Are there some advantages here?
In your case they are the same.
std::as_const is usually used to select the const version from a set of overloaded (member) functions. The following is an example from cppreference.
struct cow_string { /* ... */ }; // a copy-on-write string
cow_string str = /* ... */;
// for(auto x : str) { /* ... */ } // may cause deep copy
for(auto x : std::as_const(str)) { /* ... */ }
Even if you use for(const auto &x : str), a deep copy may still happen.
In the simple case of assigning to a reference, I doubt either option has any objective benefit over the other. Personally I prefer seeing the const attached to the variable but that's entirely subjective.
as_const() has one important benefit: it can be used to force constness without requiring a variable declaration. E.g., when calling a method where the constness of the parameter matters:
#include <iostream>
#include <utility>
void example(int const & i) {
::std::cout << "const int" << ::std::endl;
}
void example(int & i) {
::std::cout << "int" << ::std::endl;
}
int main() {
int i = 5;
example(i); // Prints "int"
example(::std::as_const(i)); // Prints "const int"
}
Consider the following line
const auto x = condition ? getLvalue() : getRvalue();
Because x is const, I don't need to copy the value returned by getLvalue, I would be happy if I could just take a reference to it. Of coure, the following would not compile
const auto& x = condition ? getLvalue() : getRvalue(); // Compilation error
as it makes no sense to make a reference to an R value.
How do I go around this problem? Is there problem or can I just trust the compiler to understand that the return type of getLvalue does not need copying?
Kind of close, but perhaps a std::variant<T, std::reference_wrapper<T>>?
You can't really use a ternary operator to assign because it requires a std::common_type, but it works fine for regular if...else:
Demo (requires C++17)
Code:
int choice = 0;
std::cin >> choice;
std::variant<int, std::reference_wrapper<int>> opt;
if (choice == 0)
opt = getRValue();
else
opt = std::ref(getLValue());
stubs for getRValue() and getLValue():
int& getLValue(){
static int foo = 42;
return foo;
}
int getRValue(){
return 1337;
}
And we can visit the variant to print:
struct visitor
{
void operator()(int _val)
{
std::cout << "rvalue value: " << _val;
}
void operator()(std::reference_wrapper<int> _val)
{
std::cout << "reference_wrapper value: " << _val << std::endl;
_val += 1;
}
};
In the reference_wrapper overload, I increment the value so we can be sure that it's still a reference.
I'm trying to understand how the copy assignment constructor works in c++. I've only worked with java so i'm really out of my waters here. I've read and seen that it's a good practice to return a reference but i don't get how i should do that. I wrote this small program to test the concept:
main.cpp:
#include <iostream>
#include "test.h"
using namespace std;
int main() {
Test t1,t2;
t1.setAge(10);
t1.setId('a');
t2.setAge(20);
t2.setId('b');
cout << "T2 (before) : " << t2.getAge() << t2.getID() << "\n";
t2 = t1; // calls assignment operator, same as t2.operator=(t1)
cout << "T2 (assignment operator called) : " << t2.getAge() << t2.getID() << "\n";
Test t3 = t1; // copy constr, same as Test t3(t1)
cout << "T3 (copy constructor using T1) : " << t3.getAge() << t3.getID() << "\n";
return 1;
}
test.h:
class Test {
int age;
char id;
public:
Test(){};
Test(const Test& t); // copy
Test& operator=(const Test& obj); // copy assign
~Test();
void setAge(int a);
void setId(char i);
int getAge() const {return age;};
char getID() const {return id;};
};
test.cpp:
#include "test.h"
void Test::setAge(int a) {
age = a;
}
void Test::setId(char i) {
id = i;
}
Test::Test(const Test& t) {
age = t.getAge();
id = t.getID();
}
Test& Test::operator=(const Test& t) {
}
Test::~Test() {};
I can't seem to understand what i should be putting inside operator=(). I've seen people returning *this but that from what i read is just a reference to the object itself (on the left of the =), right? I then thought about returning a copy of the const Test& t object but then there would be no point to using this constructor right? What do i return and why?
I've read and seen that it's a good practice to return a reference but i don't get how i should do that.
How
Add
return *this;
as the last line in the function.
Test& Test::operator=(const Test& t) {
...
return *this;
}
Why
As to the question of why you should return *this, the answer is that it is idiomatic.
For fundamental types, you can use things like:
int i;
i = 10;
i = someFunction();
You can use them in a chain operation.
int j = i = someFunction();
You can use them in a conditional.
if ( (i = someFunction()) != 0 ) { /* Do something */ }
You can use them in a function call.
foo((i = someFunction());
They work because i = ... evaluates to a reference to i. It's idiomatic to keep that semantic even for user defined types. You should be able to use:
Test a;
Test b;
b = a = someFunctionThatReturnsTest();
if ( (a = omeFunctionThatReturnsTest()).getAge() > 20 ) { /* Do something */ }
But Then
More importantly, you should avoid writing a destructor, a copy constructor, and a copy assignment operator for the posted class. The compiler created implementations will be sufficient for Test.
We return a reference from the assignment operator so we can do some cool tricks like #SomeWittyUsername shows.
The object we want to return a reference to is the one who the operator is being called on, or this. So--like you've heard--you'll want to return *this.
So your assignment operator will probably look like:
Test& Test::operator=(const Test& t) {
age = t.getAge();
id = t.getID();
return *this;
}
You may note that this looks strikingly similar to your copy-constructor. In more complicated classes, the assignment operator will do all the work of the copy-constructor, but in addition it'll have to safely remove any values the class was already storing.
Since this is a pretty simple class, we have nothing we need to safely remove. We can just re-assign both of the members. So this will be almost exactly the same as the copy-constructor.
Which means that we can actually simplify your constructor to just use the operator!
Test::Test(const Test& t) {
*this = t;
}
Again, while this works for your simple class, in production code with more complicated classes, we'll usually want to use initialization lists for our constructors (read here for more):
Test::Test(const Test& t) : age(t.getAge()), id(t.getId()) { }
Returning reference to the original object is needed for support of nested operations.
Consider
a = b = c
In the C++11, there are two versions of std::unordered_map::operator[], namely:
mapped_type& operator[] ( const key_type& k ); //1
mapped_type& operator[] ( key_type&& k ); //2
There are two questions:
1) Why the second one is necessary - the first one allows to pass constant to the function, since the first one contains the keyword const
2) For example, which version, 1 or 2, will be called in this case:
std::unordered_map<std::string, int> testmap;
testmap["test"] = 1;
Normally, the key is only used for comparison purposes, so you might wonder why rvalue semantics are necessary: a const reference should already cover that case.
But one thing to note is that operator[] can indeed create a new key/value pair: if the key wasn't already existent in the map.
In that case, if the second overload was used, then the map can safely move the provided key value in the map (while default initializing the value). It's a pretty rare and negligible optimization in my opinion, but when you're the C++ standard library, you shouldn't spare any efforts to save someone a cycle, even if it happens just once!
As for the second question, I might be wrong but it should consider the second overload as the best overload.
Edit:
There is also a valid point that it might allow you to use move-only objects as key values, even if it's a debatable decision
It's there for performance reasons. For example if the key is an rvalue, the key is moved instead of copied when a new element is inserted.
Thus, you avoid extra copy of an object/key. You can see this in the following example:
#include <iostream>
#include <unordered_map>
struct Foo {
Foo() { std::cout << "Foo() called" << std::endl; }
Foo(Foo const &other) { std::cout << "Foo(Foo const &other) called" << std::endl; }
Foo(Foo &&other) { std::cout << "Foo(Foo &&other) called" << std::endl; }
int i = 0;
};
bool operator==(Foo const &lhs, Foo const &rhs) {
return lhs.i == rhs.i;
}
void hash_combine(std::size_t& seed, const Foo& v) {
std::hash<int> hasher;
seed ^= hasher(v.i) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
struct CustomHash {
std::size_t operator()(Foo const& v) const {
std::size_t res = 0;
hash_combine(res, v);
return res;
}
};
int main() {
std::unordered_map<Foo, int, CustomHash> fmap;
Foo a;
a.i = 100;
fmap[a] = 100;
fmap[Foo()] = 1;
}
LIVE DEMO
Output:
Foo() called
Foo(Foo const &other) called
Foo() called
Foo(Foo &&other) called
As can see in the case fmap[Foo()] = 1; the rvalue object is moved in contrast with statement fmap[a] = 100; where a copy constructor is called.
I stumbled upon something similar today, and subsequently tried a few things out and noticed that the following seems to be legal in G++:
struct A {
int val_;
A() { }
A(int val) : val_(val) { }
const A& operator=(int val) { val_ = val; return *this; }
int get() { return val_; }
};
struct B : public A {
A getA() { return (((A)*this) = 20); } // legal?
};
int main() {
A a = 10;
B b;
A c = b.getA();
}
So B::getB returns a type A, after it as assigned the value 20 to itself (via the overloaded A::operator=).
After a few tests, it seems that it returns the correct value (c.get would return 20 as one may expect).
So I'm wondering, is this undefined behavior? If this is the case, what exactly makes it so? If not, what would be the advantages of such code?
After careful examination, with the help of #Kerrek SB and #Aaron McDaid, the following:
return (((A)*this) = 20);
...is like shorthand (yet obscure) syntax for:
A a(*this);
return a.operator=(20);
...or even better:
return A(*this) = 20;
...and is therefore defined behavior.
There are a number of quite separate things going on here. The code is valid, however you have made an incorrect assumption in your question. You said
"B::getA returns [...] , after it as assigned the value 20 to itself"
(my emphasis) This is not correct. getA does not modify the object. To verify this, you can simply place const in the method signature. I'll then fully explain.
A getA() const {
cout << this << " in getA() now" << endl;
return (((A)*this) = 20);
}
So what is going on here? Looking at my sample code (I've copied my transcript to the end of this answer):
A a = 10;
This declares an A with the constructor. Pretty straightfoward. This next line:
B b; b.val_ = 15;
B doesn't have any constructors, so I have to write directly to its val_ member (inherited from A).
Before we consider the next line, A c = b.getA();, we must very carefully consider the simpler expression:
b.getA();
This does not modify b, although it might superfically look like it does.
At the end, my sample code prints out the b.val_ and you see that it equals 15 still. It has not changed to 20. c.val_ has changed to 20 of course.
Look inside getA and you see (((A)*this) = 20). Let's break this down:
this // a pointer to the the variable 'b' in main(). It's of type B*
*this // a reference to 'b'. Of type B&
(A)*this // this copies into a new object of type A.
It's worth pausing here. If this was (A&)*this, or even *((A*)this), then it would be a simpler line. But it's (A)*this and therefore this creates a new object of type A and copies the relevant slice from b into it.
(Extra: You might ask how it can copy the slice in. We have a B& reference and we wish to create a new A. By default, the compiler creates a copy constructor A :: A (const A&). The compiler can use this because a reference B& can be naturally cast to a const A&.)
In particular this != &((A)*this). This might be a surprise to you. (Extra: On the other hand this == &((A&)*this) usually (depending on whether there are virtual methods))
Now that we have this new object, we can look at
((A)*this) = 20
This puts the number into this new value. This statement does not affect this->val_.
It would be an error to change getA such that it returned A&. First off, the return value of operator= is const A&, and therefore you can't return it as a A&. But even if you had const A& as the return type, this would be a reference to a temporary local variable created inside getA. It is undefined to return such things.
Finally, we can see that c will take this copy that is returned by value from getA
A c = b.getA();
That is why the current code, where getA returns the copy by value, is safe and well-defined.
== The full program ==
#include <iostream>
using namespace std;
struct A {
int val_;
A() { }
A(int val) : val_(val) { }
const A& operator=(int val) {
cout << this << " in operator= now" << endl; // prove the operator= happens on a different object (the copy)
val_ = val;
return *this;
}
int get() { return val_; }
};
struct B : public A {
A getA() const {
cout << this << " in getA() now" << endl; // the address of b
return (((A)*this) = 20);
// The preceding line does four things:
// 1. Take the current object, *this
// 2. Copy a slice of it into a new temporary object of type A
// 3. Assign 20 to this temporary copy
// 4. Return this by value
} // legal? Yes
};
int main() {
A a = 10;
B b; b.val_ = 15;
A c = b.getA();
cout << b.get() << endl; // expect 15
cout << c.get() << endl; // expect 20
B* b2 = &b;
A a2 = *b2;
cout << b2->get() << endl; // expect 15
cout << a2.get() << endl; // expect 15
}