2017-05-14 15 views
3

私はstd::forwardと混同していると思います。 std::forwardを使用している私の機能は以下のとおりですが、説明を簡単にするためには大幅に簡略化され修正されています。なぜstd :: forwardはlvalueとrvalueをrvalue参照に変換しますか?

// This is an example code to explain my question simply. 
template <typename Element> 
void add(Element&& element) { 
    static std::vector vec; 
    vec.push_back(std::forward<Element>(element)); 
} 

上記の機能で2つ試しましたが、ケース1のlvalue引数とケース2のrvalue引数

ケース1:左辺値引数

auto some_class = SomeClass(); 
add(some_class); 

ケース2:デバッガで右辺引数

add(SomeClass()); 

両方のケースは同じで、次の部分、std::forward部とstd::vector部を通過します。

std::forward一部:

template<typename _Tp> 
constexpr _Tp&& 
forward(typename std::remove_reference<_Tp>::type& __t) noexcept 
{ return static_cast<_Tp&&>(__t); } 

std::vector一部:

#if __cplusplus >= 201103L 
    void 
    push_back(value_type&& __x) 
    { emplace_back(std::move(__x)); } 

static_cast<_Tp&&>を使用しているためstd::forward部分は、右辺値参照、&&に両方のケースを変換ようです。 std::vectorstd::move()を使用しているため、両方の要素を基準値として扱います。

ケース1は、独自の名前を持っているため、ケース2はrvalueであるため、lvalueは独自の名前を持たないため、補数が必要です。 私はまた、std::forwardがケース1を左辺参照に変換し、ケース2を右辺参照に変換すると予想しています。 lvalue、rvalue、std::forwardについての私の理解は正しいですか?その場合、なぜstd::forwardが両方とも参照値参照として変換されるのは、&&です。

私が間違えた場合は、お時間を頂戴して申し訳ありません。

答えて

1

std::forwardそれはいけない右辺値参照

としての両方を変換する理由。 forwarding referenceのルールによれば、左辺値がaddに渡されると、テンプレート型引数ElementSomeClass&と推定されます。そのように第一の場合のために、std::forwardは左辺値を返しますstd::forward<SomeClass&>(element)が呼び出されます、そしてstd::forwardのインスタンス化は

// before reference collapsing 
constexpr SomeClass& && 
forward(SomeClass& __t) noexcept 
{ return static_cast<SomeClass& &&>(__t); } 

// after reference collapsing 
constexpr SomeClass& 
forward(SomeClass& __t) noexcept 
{ return static_cast<SomeClass&>(__t); } 

だろう。関数から返される左辺値は左辺値です。

ところで、第二の場合のために、templare引数Elementは、あなたが

constexpr SomeClass&& 
forward(SomeClass& __t) noexcept 
{ return static_cast<SomeClass&&>(__t); } 

右辺値参照となりstd::forwardの最後のインスタンス生成時に、上記と同じ推論を行うことができ、SomeClassと推測されますfuntionから返された値はrvalueです。


結果は奇妙に思えます.1番目のケースでは、std::vector::push_back(const T&)が呼び出されます。 (私はmcvehereを試しました)

+0

お返事ありがとうございます。私は上記の質問が奇妙であることに同意します。私は自分のコードをもう一度読んだ。もう一度ありがとうございます。 – mora

1

あなたが欠けている部分は、参照が崩壊しています。左辺値を渡すときには、TにはT&(またはconst T&)の型があります。あなたはforwardテンプレートにこれを追加する場合は、あなたが得る:

return static_cast<T& &&>(__t); 

ためのルールを崩壊参照するには、これはT&まで崩壊します。

効果的な現代のC++は、基本的にアイテム28でこれを覆う:タイプTの

  • 左辺値はT&として推定されます。
  • タイプTのR値は、Tと推定されます。

上記と参考の折りたたみ規則を参考に、std::forwardの仕組みを理解していただければと思います。

+0

参考にしていただきありがとうございます。私は再びそれを読むでしょう。 – mora

関連する問題