2012-02-01 6 views
15

조금 초보자 용 의문입니다. 벡터와 쌍 벡터가 있습니다C++ std :: 쌍의 벡터 변환 -> 처음에 새 벡터

typedef std::vector <int> TItems; 
typedef std::vector < std::pair <int, int> > TPairs; 

어떻게 펑터를 설계 한 단계

int main() 
{ 
TItems items; 
TPairs pairs; 

pairs.push_back (std::make_pair(1,3)); 
pairs.push_back (std::make_pair(5,7)); 

std::transform(items.begin(), items.end(), items.begin(), comp (&pairs)); 

return 0; 
} 

다른 벡터에 한 쌍의 모든 첫 번째 항목을 변환 할 수있는 방법이 있습니까?

class comp 
{ 
private: 
    TPairs *pairs; 

public: 
    comp (TPairs *pairs_) : pairs (pairs_) { } 

    unsigned int operator() (const unsigned int index) const 
    { 
     return (*pairs)[index].second != pairs->end(); //Bad idea 
    } 
}; 

아마도 람다 식과 루프가없는 사용자 친화적 인 방법이 있습니다. 당신의 도움을 주셔서 감사합니다.

답변

3

이미 라이브러리 함수로 제공 있기 때문에 정말, 당신은 펑터로 std::get를 사용하려면!

이 줄을 쓸 수 있다면 좋지 않을까요?

std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>); 

...하지만 그보다 약간 끔찍합니다. 이 쌍 어떤 종류를 위해 작동 할 수 있도록 std::getis overloaded는, 매개 변수 등 2 const pair& 및 3 pair&& 1. pair&을 취할 수있는 문제가

int main() { 
    std::vector<int> items; 
    std::vector<std::pair<int, int>> pairs; 

    pairs.push_back(std::make_pair(1, 3)); 
    pairs.push_back(std::make_pair(5, 7)); 

    std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), 
       (const int& (*)(const std::pair<int, int>&))std::get<0>); 

    return 0; 
} 

을 : 당신은 사용할 get을 명확하게 할 필요가 입력으로.불행하게도, 오버로드 오리지널 라인 그래서

std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>); 

수익률

error: no matching function for call to ‘transform(std::vector<std::pair<int, int> >::iterator, std::vector<std::pair<int, int> >::iterator, std::back_insert_iterator<std::vector<int> >, <unresolved overloaded function type>)’ 
    std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>); 
                        ^
... 

/usr/include/c++/4.8/bits/stl_algo.h:4915:5: note: template argument deduction/substitution failed: 
note: couldn't deduce template parameter ‘_UnaryOperation’ 
    std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>); 

그것은 당신이 추론 할 때를 요구하고 std::get의 어느 과부하 모르는, std::transform의 템플릿 형태 추론의 방법으로 얻을 std::transform의 템플릿이므로 수동으로 지정해야합니다. 함수 포인터를 올바른 형식으로 변환하면 컴파일러에 "getconst& 일 때 과부하를 사용하고 const&을 반환합니다!"

하지만 적어도 표준 라이브러리 구성 요소 (예)를 사용하고 있습니까? kotlinski @ http://ideone.com/6dfzxz

+1

누구든지 개선을 생각할 수 있습니까? 이처럼'std :: get'을 깔끔하게 사용할 수 있다는 것은 대단한 일입니다. ... 정말로'reinterperet_cast &)> (std :: get <0>)'를 사용해야 할 것입니다. 그러나 더 악화 된 것 같습니다 ... – NHDaly

+0

생각합니다. "하드"캐스트를 인수를 지정할 수있는 람다 안에 래핑 된 get 함수로 대체 할 수 있습니다 –

3

어때?

items.reserve(pairs.size()); 
for (size_t it = 0; it < pairs.size(); ++it) { 
    items.push_back(pairs[it].first); 
} 

이해하기 쉽고 디버그하기 쉽습니다.

+0

:

그리고 라인의 수로

, 그것은 다른 옵션보다 더 나쁜 없습니다 감사합니다, 그러나 이것은 일반적인 솔루션입니다. 가능하면 루프없이 원스텝 솔루션을 찾고 싶습니다. – justik

+1

당신은 사용자 친화적 인 것을 요청했습니다. 그러면 C++ 극악으로 답을 게시하는 것을 오해 할 수 있습니다. –

+0

+1 :이 경우 가장 단순합니다. 루프를 피하는 것이 왜 단순합니까? – stefaanv

15

우선, transform의 세 번째 인수로 back_inserter을 사용하여 변환 된 값이 벡터의 뒷면으로 푸시되도록해야합니다.

두 번째로, 한 쌍의 int를 취하고 첫 번째를 반환하는 일종의 functor가 필요합니다. 이 수행해야합니다

이제
int firstElement(const std::pair<int, int> &p) { 
    return p.first; 
} 

함께 조각을 넣어 :

TPairs pairs; 
pairs.push_back(std::make_pair(1, 3)); 
pairs.push_back(std::make_pair(5, 7)); 

TItems items; 
std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), 
       firstElement); 

를이 코드 후, items 1, 5

+0

@ Freirich Raabe : 감사합니다. – justik

+2

사용자 정의 함수 대신 [std :: get <0>] (http://en.cppreference.com/w/cpp/utility/tuple/get)을 사용하는 영리한 방법이 있습니까? – NHDaly

2

를 포함하는 방법 std::bind 사용에 대한?

std::transform(pairs.begin(), 
       pairs.end(), 
       std::back_inserter(items), 
       std::bind(&TPairs::value_type::first, std::placeholders::_1)); 

10

는 frerich 년대 또는 C++ 03 kotlinski의 답변을 참조 (비 C++ 11 코드 boost::bind에 의해 std::bind 교체). 람다와

C++ 11 솔루션 :

std::transform(pairs.begin(), 
       pairs.end(), 
       std::back_inserter(items), 
       [](const std::pair<int, int>& p) { return p.first; }); 
+0

죄송 합니다만, "아니오 람다"요구 사항을 알지 못했지만 간단하고 언어의 일부인 이유는 무엇입니까? – stefaanv

+0

저는 컴파일러의 한계 또는 작업장의 요구 사항으로 인해 여기 주변 사람들의 대부분이 실제로 사용할 수있는 C++ 언어의 일부가 아니라고 생각합니다. –