正しい転送を保証するために std::forward でテンプレート引数の推論を無効にする
VS2010 の std::forward の定義を検討してください:
template inline
_Ty&& forward(typename identity<_Ty>::type& _Arg)
{ // forward _Arg, given explicitly specified type parameter
return ((_Ty&&)_Arg);
}
アイデンティティ テンプレートの目的は、テンプレート引数の推定を無効にすることです。このシナリオでこれが重要なのはなぜですか?
テンプレート引数の推論は、誤った型の推論につながります。型 X のオブジェクトへの右辺値参照がパラメーター型 T& のテンプレート関数に渡される場合、テンプレート引数の推定により T が X として推論され、パラメーター型 X& が生成されます。ただし、完全転送の場合、パラメーターには名前があるため、パラメーターは左辺値になります。したがって、 std::forward でテンプレート引数の推論を使用すると、推論されたパラメータの型が左辺値参照または const 左辺値参照になります。
template
T&& forward_with_deduction(T&& obj)
{
return static_cast次の例を考えてみましょう:
void test(int&){}
void test(const int&){}
void test(int&&){}
template
void perfect_forwarder(T&& obj)
{
test(forward_with_deduction(obj));
}
int main()
{
int x;
const int& y(x);
int&& z = std::move(x);
test(forward_with_deduction(7)); // 7 is an int&&, correctly calls test(int&&)
test(forward_with_deduction(z)); // z is treated as an int&, calls test(int&)
// All the below call test(int&) or test(const int&) because in perfect_forwarder 'obj' is treated as
// an int& or const int& (because it is named) so T in forward_with_deduction is deduced as int&
// or const int&. The T&& in static_cast<T&&>(obj) then collapses to int& or const int& - which is not what
// we want in the bottom two cases.
perfect_forwarder(x);
perfect_forwarder(y);
perfect_forwarder(std::move(x));
perfect_forwarder(std::move(y));
}
この例では、perfect_forwarder のパラメーターがその名前により lvalue または const lvalue 参照として扱われるため、完全転送は失敗します。これにより、forward_with_deduction で不正な型推論が発生し、望ましくない static_cast セマンティクスが発生します。
std::forward の ID テンプレートでテンプレート引数の推論を無効にすると、std::forward が常に右辺値参照を返すようになります。これは、左辺値と右辺値の正しい完全転送。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3