任何人都知道为什么第一个程序编译但第二个程序不编译?唯一的区别是第一个使用普通函数,第二个使用模板函数。为什么重载分辨率在模板和非模板函数的位域上表现不同?
回答时请参阅标准段落。感谢。
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);
}
编译器错误:
[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.
答案 0 :(得分:4)
错误很明显,您不能将非常量引用带到位域。 [class.bit] / 3 :
运营商地址&amp;不应用于位域,因此没有指向位域的指针。非const引用不应绑定到位字段(8.5.3)。 [注意:如果初始化器为const T&amp;类型的参考是一个引用位字段的左值,引用绑定到临时初始化以保存位字段的值;引用不直接绑定到位字段。见8.5.3。 - 后注]
重载决策行为不同的原因与通用引用有关。参考折叠规则和模板使这个:
template <typename T>
void f(T&& x) {}
导致T&&
在应用于非限定左值 int&
时被推断为int
,这是x.x
的情况。在这种特殊情况下,您只剩下:
void f(int& x){}
void f(int const& x){}
和第一个,从f(T&& x)
的参考折叠规则获得的那个,可以清楚地看到它比后一个更好。