考虑以下代码:
#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吗?只是未定义的行为,因此它们都是“正确的”吗?
答案 0 :(得分:3)
允许func(const T &x)
是因为GCC会为打包成员创建一个临时文件。
添加转发引用重载时,函数调用将解析为看起来像func(uint32_t&)
的函数。由于它是可变的左值引用,因此没有更好的匹配,因此无法创建任何临时值,并且重载解析也会失败。
您可以通过强制const允许编译器再次创建临时文件来使其工作:
func(std::as_const(s).f1);