I am comparing the class. For the below code
#include <string>
#include <set>
#include <tuple>
#include <cassert>
enum class e : bool
{
positive = true,
negetive = false
};
class A
{
public:
int a;
e e1 : 1;
friend bool operator==(const A&, const A&);
};
bool operator==(const A& lhs, const A& rhs) {
auto tie = [](const A& a1) {
return std::tie(a1.a, a1.e1);
};
auto x1 = tie(lhs);
auto x2 = tie(rhs);
return x1 == x2;
}
int main()
{
A a1;
a1.a = 10;
a1.e1 = e::positive;
A b1;
b1.a = 10;
b1.e1 = e::positive;
assert(a1 == b1);
}
Output is :
a.out: main.cpp:44: int main(): Assertion `a1 == b1' failed.
Which is wrong, as two of the classes are the same.
However, if I change the line of code from e e1 : 1;
to e e1;
it gives the right result.
First of I am wondering what does : does in this case? Why the result is wrong after adding this?
Code can be seen here.
Thanks in advance.
This function:
auto tie = [](const A& a1) {
return std::tie(a1.a, a1.e1);
};
returns a std::tuple<int const&, e const &>
. Even though the fields that the tuple
store are references, there is a special rule for bit fields where a temporary copy of the bit field is made, and a reference is bound to that temporary. This means when you return from the function, the reference to the bit field is dangling, leading to undefined behavior when you use that field of the tuple
later.
You can fix this by explicitly specifying the return type:
auto tie = [](const A& a1) -> std::tuple<int, e> {
return std::tie(a1.a, a1.e1);
};
Here's a demo.
Alternatively, you could return a tuple
that decays the argument types, and avoids the dangling issue, like this:
auto tie = [](const A& a1) {
return std::make_tuple(a1.a, a1.e1);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With