Consider the following code:
#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 gives the following error:
<source>: In function 'int main()':
<source>:16:12: error: cannot bind packed field 's.S::f1' to 'unsigned int&'
16 | func(s.f1);
| ~~^~
It appears that GCC is choosing to not allow universal references to members of a packed struct, presumably due to alignment concerns. However, clang compiles the code just fine.
Adding to my confusion is that if I remove the (T &&x)
overload, it works "just fine" if only the (const T &)
overload exists. I would expect that if it can't use the universal-ref overload, then it would just fall back on const-ref version... but it doesn't.
Is clang incorrect here? Is GCC? Is it just undefined behavior and therefore they are both "right"?