2017-12-20 7 views
5

次のコード:は、STDの動作です::右辺値参照のタプルに危険を取得しますか?

#include <tuple> 

int main() 
{ 
    auto f = []() -> decltype (auto) 
    { 
    return std::get<0> (std::make_tuple (0)); 
    }; 

    return f(); 
} 

(サイレント)未定義の動作を使用してコードを生成 - make_tupleによって返された一時的な右辺値は、STDを介して伝播される:: <を得る>とdecltype(自動)を介して、戻り値の型の上に。だから、スコープ外になったことを一時的に参照を返してしまいます。ここでそれを参照してくださいhttps://godbolt.org/g/X1UhSw

さて、あなたはdecltype(auto)の私の使用は故障していると主張することができます。しかし、(タプルのタイプはstd::tuple<Foo &>かもしれない)私の汎用コードで私はいつもコピーを作成する必要はありません。私は実際にタプルから正確な値または参照を抽出したいと思います。

私の気持ちはstd::getのこのオーバーロードは危険であるということである。

template< std::size_t I, class... Types > 
constexpr std::tuple_element_t<I, tuple<Types...> >&& 
get(tuple<Types...>&& t) noexcept; 

タプル要素に左辺値参照を伝播しながら、私はそれは右辺値参照を保持しているとは思わない、おそらく賢明です。

私は、標準化委員会は非常に慎重を介してこれを考えたと確信しているが、これが最良の選択肢と考えた理由を誰も私に説明できますか?我々はstd::tuple{foo{}}が一時的であることを知って、それはconsume_tuple_first(std::tuple{foo{}})表現の全期間のために生きるということ、この場合

void consume(foo&&); 

template <typename Tuple> 
void consume_tuple_first(Tuple&& t) 
{ 
    consume(std::get<0>(std::forward<Tuple>(t))); 
} 

int main() 
{ 
    consume_tuple_first(std::tuple{foo{}}); 
} 

+0

* "rvalueの参照には当てはまりません" * - あなたが 'forward_as_tuple'を実行するとします。値のカテゴリを保持する必要があります。または、関数の戻り値から1つの値を抽出したい場合。 – StoryTeller

+0

ありがとうございますが、私は本当にそれが価値のカテゴリーを保持しているとは確信していません。たとえば、 'std :: tuple 'を返す関数があり、 'std :: get <0>'を呼び出すと、 'int &&'ではなく 'int'を得ることが期待されます。あなたは何か他のものがほしいと思う具体的な例を私に与えることができますか? –

+1

効果的な構造化バインディングには 'get'のオーバーロードが必要ではありませんか? –

答えて

2

は、次の例を考えてみましょう。

不必要なコピーや移動を避けたいが、foo{}の一時性はまだconsumeに伝播しています。

それを行う唯一の方法は、std::getリターン一時的std::tupleインスタンスで呼び出さ右辺値参照を持つことです。 std::get<0>(t)std::get<0>(std::forward<Tuple>(t))変更

live example on wandbox


は、コンパイルエラー(予想通り)(on wandbox)を生成します。

template <typename Tuple> 
auto myget(Tuple&& t) 
{ 
    return std::get<0>(std::forward<Tuple>(t)); 
} 

template <typename Tuple> 
void consume_tuple_first(Tuple&& t) 
{ 
    consume(myget(std::forward<Tuple>(t))); 
} 

live example on wandbox


が、これが考慮された理由、誰もが私に説明することができます追加の不必要な移動に値結果で返すget選択肢を持つ


最高のオプション?

それがシームレスに一時右辺値参照タプルにアクセス伝播し、オプションの汎用コードを可能にしますので。値を返す代わりに、不要な移動操作が発生する可能性があります。

+0

ああ、私は参照してください。だから私は、 "safe_get"を返すunadorned型は余分な動きを引き起こします。 IMHOは安全のために払う価値のある価格になるだろうが、少なくとも議論の余地があると思う。あなたの答えに多くの感謝! –

関連する問題