3

最初のプログラムがコンパイルされる理由を誰もが知っていますが、2番目のプログラムはコンパイルされませんか?唯一の違いは、最初のものは通常の機能を使用しますが、2番目のものはテンプレート機能を使用することです。テンプレート関数と非テンプレート関数のビットフィールドで過負荷解決の動作が異なるのはなぜですか?

回答する際は、標準の段落を参照してください。ありがとう。

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.
4

1 に答える 1

4

エラーは非常に明確です。ビットフィールドの非定数参照を取得することはできません。[class.bit] / 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)であり、後のものよりもよく一致していることがはっきりとわかります。

于 2012-12-24T22:42:25.430 に答える