Anyone knows why the first program compiles but second one doesn’t? The only difference is that the first one uses normal function but the second one uses template function. Why the overload resolution behaves differently on bitfield for template and non-template function?
Please refer to paragraphs in standard when answering. Thanks.
a.cpp
struct X {
int x : 20;
int y : 12;
};
void f(const int& x) {}
void f(int&& x) {}
int main() {
X x;
f(x.x);
}
b.cpp
struct X {
int x : 20;
int y : 12;
};
template <typename T>
void f(T&& x) {}
template <typename T>
void f(const T& x) {}
int main() {
X x;
f(x.x);
}
Compiler errors:
[hidden]$ g++ -v 2>&1 | tail -n 1
gcc version 4.7.2 20120921 (Red Hat 4.7.2-2) (GCC)
[hidden]$ clang++ -v 2>&1 | head -n 1
clang version 3.3
[hidden]$ g++ -std=c++11 a.cpp
[hidden]$ g++ -std=c++11 b.cpp
b.cpp: In function ‘int main()’:
b.cpp:14:8: error: cannot bind bitfield ‘x.X::x’ to ‘int&’
[hidden]$ clang++ -std=c++11 a.cpp
[hidden]$ clang++ -std=c++11 b.cpp
b.cpp:14:5: error: non-const reference cannot bind to bit-field 'x'
f(x.x);
^~~
b.cpp:2:7: note: bit-field is declared here
int x : 20;
^
1 error generated.
The error is quite clear, you cannot take non-const references to bitfields. [class.bit]/3:
The reason overload resolution behaves differently has to do with Universal References. Reference collapsing rules and templates make this:
result in
T&&to be deduced asint&when applied to a non-const lvalueint, which is the case forx.x. In that particular case, you are left with:and the first one, the one obtained from reference collapsing rules on
f(T&& x), it can be clearly seen to be a better match than the later one.