模板的重载解析中的位字段

bit-field in overload resolution for template

提问人:Kan Li 提问时间:12/25/2012 更新时间:12/28/2012 访问量:2870

问:

有人知道为什么第一个程序可以编译,而第二个程序却不编译吗?唯一的区别是第一个使用普通函数,而第二个使用模板函数。为什么模板和非模板函数的重载分辨率在位域上的行为不同?

回答时请参考标准中的段落。谢谢。

一个.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.
C++ GCC C++11 叮当声

评论

0赞 K-ballo 12/25/2012
MSVC 11 做对了这一点,所以我仍然不确定这是标准缺陷还是编译器错误。您能否在编译器中尝试第一个测试用例,但将其替换为 ?int&& xint& x
0赞 Ben Voigt 12/25/2012
@K-ballo:这在 gcc 中也失败了。ideone.com/WXJOegMSVC 接受它并不奇怪,MSVC 不恰当地将非常量引用绑定到临时引用。
0赞 K-ballo 12/25/2012
@Ben Voigt:我想......现在要弄清楚哪个编译器是正确的
0赞 K-ballo 12/25/2012
@Ben Voigt:实际上,MSVC 绑定到此处的 const 引用。
0赞 Ben Voigt 12/25/2012
@K-ballo:哇。它是否也绑定到非常量引用(如果你不给它另一个选择)?

答:

4赞 K-ballo 12/25/2012 #1

错误非常明显,您不能对位域进行非常量引用[类位]/3

地址运算符&不应应用于位字段,因此没有指向位字段的指针。非常量引用不应绑定到位域 (8.5.3)。[ 注意:如果 const T& 类型的引用的初始值设定项是引用位字段的左值,则引用将绑定到临时初始化以保存位字段的值;引用不直接绑定到位字段。见 8.5.3。——尾注 ]

重载分辨率行为不同的原因与通用引用有关。引用折叠规则和模板使以下内容:

template <typename T>
void f(T&& x) {}

结果被推导为当应用于非常量左值时,这就是 的情况。在这种特殊情况下,您只剩下:T&&int&intx.x

void f(int& x){}
void f(int const& x){}

而第一个,就是从参考折叠规则中得到的那个,可以清楚地看出它比后一个更匹配。f(T&& x)

评论

0赞 Kan Li 12/25/2012
糟糕的asnwer。这就是我要问的:为什么对于模板情况,重载分辨率会转到 f(T&&) 而不是 f(const T&),而对于正常函数情况,重载解析会转到 f(const int&) 而不是 f(int&&)。
0赞 K-ballo 12/25/2012
@icando:使用左值调用时,不会因引用折叠规则而重载。f(int&&)
0赞 Kan Li 12/25/2012
如果编译器认为是比更好的分辨率,为什么它不认为比更好的分辨率?const int&int&&const T&T&&
0赞 K-ballo 12/25/2012
@icando:没有要解析的重载,引用折叠规则使模板化版本为 .int&&int&
1赞 Kan Li 12/25/2012
好的,所以这基本上是C++标准的缺陷。位域不能绑定到非常量引用,但重载解析首选非常量引用而不是常量引用。