通用引用和压缩字段

时间:2019-06-03 13:42:00

标签: c++ packed-structure

考虑以下代码:

#include <cstdint>

struct S {
  uint32_t f1;
} __attribute__((packed)); // removing this attribute makes things work.

template <class T> void func(const T &x) {}
template <class T> void func(T &&x) {} // commenting out this line makes it "work"

int main() {
    S s;
    func(s.f1); // Error here in GCC, but not clang
}

GCC出现以下错误:

<source>: In function 'int main()':
<source>:16:12: error: cannot bind packed field 's.S::f1' to 'unsigned int&'
   16 |     func(s.f1);
      |          ~~^~

似乎是由于对齐问题,GCC似乎选择不允许普遍引用打包结构的成员。但是,clang可以很好地编译代码。

让我感到困惑的是,如果我删除了(T &&x)重载,并且仅存在(const T &)重载,它就“很好”地工作。我希望如果它不能使用Universal-ref重载,那么它只会使用const-ref版本...但事实并非如此。

这里的lang不正确吗?是GCC吗?只是未定义的行为,因此它们都是“正确的”吗?

1 个答案:

答案 0 :(得分:3)

允许func(const T &x)是因为GCC会为打包成员创建一个临时文件。

添加转发引用重载时,函数调用将解析为看起来像func(uint32_t&)的函数。由于它是可变的左值引用,因此没有更好的匹配,因此无法创建任何临时值,并且重载解析也会失败。

您可以通过强制const允许编译器再次创建临时文件来使其工作:

func(std::as_const(s).f1);