4

このフォームの例をよく目にします。

template <typename T, typename U>
auto add(T&& t, U&& u) -> decltype(std::forward<T>(t) + std::forward<U>(u))
{
    return std::forward<T>(t) + std::forward<U>(u);
}  

しかし、私はあえてこれがより正しい方法であると言います:

template <typename T, typename U>
auto add(T&& t, U&& u) -> decltype(t + u)//no forwarding here
{
    return std::forward<T>(t) + std::forward<U>(u);
}

なんで?何よりもまず、この例のdecltypeはリターンタイプを推測するだけでよいので、(t + u)はリターンタイプではなく(std :: forward(t)+ std :: forward(u))、2つのverによって生成される2番目のコードは同一であり、3番目のdecltype(u + t)はより直接的であり、実装の「根性」を引き出すことなく、プログラマーの意図が何であるかを正確に表現します。

このテーマについてどう思いますか?

4

3 に答える 3

3

最初のバージョンは、関数本体が返すものと正確に一致するため、より正確です。すでに指摘したように、それは単にその保証はありません

decltype(std::forward<T>(t) + std::forward<U>(u))

と同じタイプになります

decltype(t + u)

間違いなく、これは非常にまれなケースですが、「正しい」方法はstd::forwardを使用することです。

于 2011-04-27T12:46:06.100 に答える
2

decltype(t + u)では、変数tuはすでに右辺値参照ではなく、単純な左辺値参照として扱われるため、追加のが必要ですstd::forward。(少なくとも、それは私がそれを理解する方法です。しかし間違っている可能性があります。)

于 2011-04-27T10:01:47.450 に答える
2

一般に、違いがあるという賢明なユースケースは考えられませんが、操作の実装が右辺値参照と右辺値で異なり、言語規則で戻り値が指定されていない場合もあると思います。異なるオーバーロードのタイプは同じである必要があります(常識がそれを指示する場合でも)。

したがって、一般的なケースでは違いはなく、違いがある場合は、テンプレート自体よりもはるかに悪い問題に対して特別な注意と注意が必要です...

// sick corner case:
struct type {};
int operator+( type&& lhs, type&& rhs );
double operator+( type const & lhs, type const & rhs );

右辺値参照にさまざまなオーバーロードを提供したい状況を考えることができます(operator+連結として提供するリストの実装を検討してください。次に、右辺値参照を使用したオーバーロードは、ポインターを操作して、引数は空です)が、結果のタイプが引数のl / rvalue-nessに依存する場合、それは完全に混乱します。

于 2011-04-27T10:07:51.137 に答える