添加 : 在变量前面会给出错误的结果

Swa*_*nil 4 c++ c++11 std-tie

我在比较班级。对于下面的代码

#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);

}
Run Code Online (Sandbox Code Playgroud)

输出是:

a.out: main.cpp:44: int main(): Assertion `a1 == b1' failed.
Run Code Online (Sandbox Code Playgroud)

这是错误的,因为两个类是相同的。

但是,如果我将代码行更改为e e1 : 1;e e1;则会给出正确的结果。

首先,我想知道 : 在这种情况下是什么?为什么加上这个后结果是错误的?

代码可以在这里看到

提前致谢。

cig*_*ien 7

这个功能:

auto tie = [](const A& a1) {
    return std::tie(a1.a, a1.e1);
};
Run Code Online (Sandbox Code Playgroud)

返回一个std::tuple<int const&, e const &>. 即使tuple存储的字段是引用,对于位字段也有一个特殊规则,其中制作了位字段的临时副本,并且引用绑定到该临时文件。这意味着当您从函数返回时,对位字段的引用是悬空的,当您使用后者的该字段时会导致未定义的行为tuple

您可以通过显式指定返回类型来解决此问题:

auto tie = [](const A& a1) -> std::tuple<int, e> {
    return std::tie(a1.a, a1.e1);
};
Run Code Online (Sandbox Code Playgroud)

这是一个演示

或者,您可以返回一个tuple衰减参数类型,并避免悬空问题,如下所示:

auto tie = [](const A& a1) {
    return std::make_tuple(a1.a, a1.e1);
};
Run Code Online (Sandbox Code Playgroud)

  • 来自 [cppreference](https://en.cppreference.com/w/cpp/language/bit_field) 的@NathanOliver:“当从位字段初始化常量引用时,会创建一个临时变量(其类型是位的类型)字段),使用位字段的值初始化副本,并且引用绑定到该临时值。”。可恶的。 (3认同)
  • 使用了哪些局部变量?`a1` 是一个引用, (2认同)
  • 如果您在编译时与“static_assert”进行比较,clang 会生成一条非常好的错误消息,解释发生的情况,[此处演示](https://godbolt.org/z/7M1Wxq)。 (2认同)