2016-10-01 11 views
3

How do I write a range pipeline that uses temporary containers?을 고려하십시오. 문제는 전망이 그 선물 경량 래퍼 어떤 주어진 함수범위 -v3의 'partial_sum'은 소유하지 않은 참조 의미와 어떻게 상충하지 않습니까?

std::vector<T> f(T t); 

(가 상단 답에서 차입) the restriction 준수하면서

것을를 사용하여 각 요소 T 변환보기를 구축하는 방법입니다 일부 사용자 정의 방법으로 요소의 기본 시퀀스를 변경하거나 복사하지 않고도 볼 수 있습니다. 조회수는 작성 및 복사 비용이 적게 들며 비 소유 참조 시맨틱을 가지고 있습니다.

기본적으로 모든 제한 사항으로 인해보기를 통해 수행 할 수 없다는 점에 동의합니다.


이 라이브러리가 partial_sum을 지원하는 라이브러리와 어떻게 어울리는 지 이해할 수 없습니다.

는 다음과 같은 영광의 정수를 고려

#include <vector> 
#include <iostream> 
#include <memory> 
#include <range/v3/all.hpp> 

using namespace ranges; 

struct glorified_int { 
    explicit glorified_int(int i) : m_i{std::make_shared<int>(i)} {} 
    operator int() const { return *m_i; } 
    std::shared_ptr<int> m_i; 
}; 

glorified_int operator+(const glorified_int &lhs, const glorified_int &rhs) { 
    glorified_int ret{(int)lhs + (int)rhs}; 
    return ret; 
} 

그것은 기본적으로 그냥 초기화 추출물 및 추가하는 것을 허용 할 std::shared_ptr에 저장 클래스에 int을 래핑합니다. W.r. 소유하고 있지 않은 참조 의미론, 나는 그것과 컨테이너 사이의 근본적인 차이점을 std::vector과 같이 볼 수 없다.

범위는하지만,이에 partial_sum을 적용하는 문제가있는 것 같지 않습니다 밖으로

인쇄

$ ./a.out 
1 
3 

는 (의 영광 정수) 3 여기에 임시 아닌가? 확실히 원래 시퀀스의 일부는 아닙니다. 또한 부분 합은 상태 저장 변환이므로 범위 보증 범위는 어떻게 될 수 있습니까?

조회수는 생성하고 복사하는 것이 저렴하며 참조하지 않은 참조 의미가 없습니다.

보기가 누적 개체만큼 복사하는 것이 비쌉니다.

도 (즉,이 동작되지 않음)이 상기 체인에 아무런 문제가 없다는 것을

참고

vi | view::partial_sum() | view::take(10); 

차이는 다음 무엇인가?


전체 코드 뷰가 걸릴 또는 복사의 소유권을 필요로하거나, 입력 범위의 요소를 수정하지 않는다는 것입니다 뷰를 만드는 것

#include <vector> 
#include <iostream> 
#include <memory> 
#include <range/v3/all.hpp> 

using namespace ranges; 

struct glorified_int { 
    explicit glorified_int(int i) : m_i{std::make_shared<int>(i)} {} 
    operator int() const { return *m_i; } 
    std::shared_ptr<int> m_i; 
}; 

glorified_int operator+(const glorified_int &lhs, const glorified_int &rhs) { 
    glorified_int ret{(int)lhs + (int)rhs}; 
    return ret; 
} 

int main() { 
    std::vector<glorified_int> vi{ glorified_int{1}, glorified_int{2} }; 
    for(const auto &ps: vi | view::partial_sum()) 
     std::cout << ps << std::endl; 
    vi | view::partial_sum() | view::take(10); 
} 

답변

3

. 그러나 어떤 관점도 필요하지 않습니다. take() 또는 filter()일부 상태 (각각 카운터 및 술어)가 있습니다.

이 특정 경우에 partial_sum은 입력 범위의 요소를 소유 할 필요가 없습니다. 그것이 입력 범위의 작업입니다. 또한 복사하거나 수정할 필요가 없습니다. 그것은 단순히 자신의 상태를 추적 할 필요가 있습니다 - 누적 합계 (optional<glorified_int>)와 합계를 수행하는 이진 함수 (plus). 자체 오브젝트 중 하나를 소유하지만 해당 오브젝트는 입력 범위 외부에 존재합니다. 그래도 여전히보기가되며 상태있는 것입니다.

당신은 쓰기 :

뷰가 축적 개체로 복사하기 위해 비싸다.

이것은 사실입니다. 그러나 그것은 많은 관점에서도 마찬가지입니다. transform()은 뷰를 변환하는 데 사용하는 함수만큼 복사하는 데 비용이 많이 들지만 엄청난 상태의 비싸고 메모리를 할당하는 괴물이있을 수 있습니다.

에릭이 작성 및 복사 비용이 저렴하다고 말하면 나는 새로운 범위를 만들기 위해 전체 입력 범위를 만들고 복사한다는 맥락에서 의미한다고 생각합니다.

// cheap version 
for(const auto &ps: vi | view::partial_sum()) { ... } 

// expensive version 
std::vector<glorified_int> partial_sums; 
if (!vi.empty()) { 
    auto it = vi.begin(); 
    partial_sums.emplace_back(*it++); 
    for (; it != vi.end(); ++it) { 
     partial_sums.emplace_back(*it + partial_sums.back()); 
    } 
} 
for (const auto &ps : partial_sums) { ... } 

우리는 분명히 전체가 필요하지 않습니다 : partial_sum() 해당 요소는 할당을 필요로하기 때문에 귀하의 경우 싸지 않다 실행중인 합계를 유지하기 위해 필요하지만, 그것은 여전히 ​​행동 ​​기반 partial_sum 작성하는 것보다 훨씬 저렴 partial_sums 벡터 우리가 원하는 것을 할 수 있습니다 (우리가 그것을 필요로한다면, 잘, 그 주위에). 이 뷰는 우리에게 부분 합계를보기위한 저렴한 방법을 제공합니다.

+0

답변 해 주셔서 감사합니다. 같은 비유로, 왜 전술 한 질문에서 국가는 역 참조 된 반복자에 함수를 적용함으로써 형성된 벡터가 될 수 없었는가? 즉, 누적 된 것이 일시적인 소유로 간주되지 않는 이유는 무엇입니까?하지만 역 참조 된 반복기에 함수를 적용한 결과는 반대라고 생각합니다. –

+0

@AmiTavory 가설적인'view :: join()'은 입력을 올바르게 전달하기 위해서 전체 입력 범위의 소유권을 가져야 만하기 때문에. – Barry

+0

다시 한번 감사드립니다. 당신이 의미하는 것을 모호하게보기 시작합니다. 가입 소스 (내가 건너 뛴)와 [this] (https://github.com/ericniebler/range-v3/issues/442)를 읽습니다. –