2017-12-20 25 views
5

다음 코드 :rvalue-reference 튜플에서 std :: get의 동작이 위험합니까?

#include <tuple> 

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

    return f(); 
} 

(조용히) 정의되지 않은 동작과 코드를 생성 - make_tuple에 의해 반환되는 일시를 rvalue는 표준 : <을 얻을 통해 전파>하고 반환 형식 상 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; 

동안, 나는이를 rvalue 참조에 대한 보유하고 생각하지 않습니다.

나는 표준위원회가이를 매우 신중하게 생각했지만, 누구나 이것이 왜 최선의 선택이라고 생각하는지 설명 할 수 있을까요? 우리가 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 references에 해당한다고 생각하지 않습니다."* - 'forward_as_tuple'이라면 가능합니다. 가치 범주를 보존하려고합니다. 또는 함수 반환 값에서 하나의 값을 추출하려는 경우 – StoryTeller

+0

고마워,하지만 나는 그것이 가치 범주를 보존하고 있는지 정말로 모르겠다. 예를 들어'std :: tuple '을 반환하는 함수가 있고'std :: get <0>'을 호출하면 나는'int && '가 아닌 일반'int'를 얻을 것으로 기대합니다. 당신이 다른 것을 원할 때 구체적인 예를 들어 줄 수 있습니까? –

+1

효과적인 구조화 된 바인딩에 필요한 'get'의 과부하가 아닙니까? –

답변

2

는 다음과 같은 예를 생각해 보자.

우리는 불필요한 복사 및 이동을 피하려고하지만 foo{}의 임시 성도를 consume으로 전파합니다.

그 일을하는 유일한 방법은 std::get 반환 임시 std::tuple 인스턴스에 호출됩니다 를 rvalue 참조을 가진 것입니다. std::get<0>(t)std::get<0>(std::forward<Tuple>(t)) 변경


live example on wandbox

는 (예상대로) 컴파일 오류 ( on wandbox)를 생산하고 있습니다.


추가 불필요한 움직임에 값을 결과로 반환하는 get 대안을 갖는

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


그러나이 고려 된 사람이 왜 나에게 설명 할 수있는 최선의 선택은?

이 원활하게 한 임시 를 rvalue 참조 튜플에 접근 전파 옵션 일반적인 코드를 할 수 있기 때문에. 값으로 반환하는 대신 불필요한 이동 작업이 발생할 수 있습니다.

+0

알았어. 그래서 꾸밈없는 타입을 리턴하는 "safe_get"은 추가 이동을 야기합니다. IMHO는 안전을 위해 값을 치를만한 가치가있는 가격이지만 적어도 논쟁의 여지가 있음을 알 수 있습니다. 귀하의 답변에 많은 감사드립니다! –