STL 알고리즘에는 std::copy와 std::remove_copy가 정의되어 있습니다.

이름에서 추측할 수 있듯이 std::copy는 두 컨테이너간 element 복사를 합니다.
또한 std::remove_copy는 특정한 element를 제외하고 복사 합니다.

std::copy_if 는 STL 알고리즘에 포함되어 있지 않습니다.
그 대신 std::remove_copy_if 가 정의되어 있습니다.

왜 그럴까요?

C++ 표준화 위원회에서 살짝 빠트린(?) 걸까요?

그렇게 생각하기엔 뭔가 이상하다고 생각되시죠. 저도 그렇습니다. ㅎㅎ

그렇다면, std::remove_copy_if는 어떻게 생겼을까요?
template< class _InIt,
	class _OutIt,
	class _Pr > inline
	_OutIt _Remove_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, _Range_checked_iterator_tag)
	{	// copy omitting each element satisfying _Pred
	_DEBUG_RANGE(_First, _Last);
	_DEBUG_POINTER(_Dest);
	_DEBUG_POINTER(_Pred);
	for (; _First != _Last; ++_First)
		if (!_Pred(*_First))
			*_Dest++ = *_First;
	return (_Dest);
	}
위와 같이 생겼습니다. 무슨 뜻인지 모르시겠다구요.

딱! 보면...
저도 잘 모르겠습니다.(딱 봐서 알기엔 아직 실력이 부족해서요. ㅎㅎ)

아무래도 첫번째 컨테이너의 First Iterator에서 Last Iterator까지
반복문을 돌면서 조건식에 일치하지 않는 iterator만
두번째 컨테이너에 하나씩 element 복사를 하는 로직으로 보입니다.

헉. 조건에 일치하지 않는? 뭔가 이상하죠. ㅎㅎ

제거하면서 복사해야 하니까 조건에 일치하지 않는 것들만 복사하는게 맞는데요.
뭐가 이상하다는거죠?

눈치 빠르신 분은 느끼셨겠지만 조건에 일치하는 값만 복사하게 한다면?

조건에 일치하는 값만 복사하게 한다는 것은 결국 std::copy_if로 사용한다는 것입니다.

오호~ 그렇다면 조건에 일치하지 않는 것을 조건에 일치하게 만들어서 쓰면 된다는 것이군요.

그래서 아래와 같이 std::remove_copy_if를 -> std::copy_if 처럼 사용할 수 있습니다.
그 방법은 바로 조건문을 반전시키는 std::not1, std::not2 입니다.
	std::vector< int > vecInteger;
	vecInteger.push_back( 1 );
	vecInteger.push_back( 2 );
	vecInteger.push_back( 3 );
	vecInteger.push_back( 2 );
	vecInteger.push_back( 5 );
		
	std::vector< int > vecOutput;
	std::remove_copy_if( vecInteger.begin(), vecInteger.end(), std::back_inserter( vecOutput ), std::bind2nd( std::equal_to< int >(), 2 ) );
사용자 삽입 이미지
이 결과는 이렇습니다.

 그렇다면 아래와 같이 std::not1을 활용하면,
	std::vector< int > vecInteger;
	vecInteger.push_back( 1 );
	vecInteger.push_back( 2 );
	vecInteger.push_back( 3 );
	vecInteger.push_back( 2 );
	vecInteger.push_back( 5 );
		
	std::vector< int > vecOutput;
	std::remove_copy_if( vecInteger.begin(), vecInteger.end(), std::back_inserter( vecOutput ), std::not1( std::bind2nd( std::equal_to< int >(), 2 ) ) );
사용자 삽입 이미지
우리가 원한 결과입니다.
조건자에 std::not 시리즈를 사용하기 위해서는 술어 함수, 즉 Logical 함수가 필요합니다.
술어함수가 되기 위해선 조건식 함수자가 std::unary_function, std::binary_function을 상속 받아야 합니다.
그 이유는 result_type이 필요하다고 합니다. 사실 bool을 리턴하긴 해야 하니까요.

따라서 std::copy_if를 쓰시려면 std::remove_copy_if와 std::not 조합으로 쓰시면 되구요.
혹시 std::remove_copy_if가 보이신다면 std::not1, std::not2 함수가 보이는지 살펴보세요.

좀더 명시적으로 사용하려면 std namespace 안에 copy_if를 정의하는 것도 방법이겠지만,
표준화 위원회에서는 std namespace안에 다른 함수를 정의하는 것을 추천하지 않는다고 합니다.

라이브러리 사용자 입장에서는 일단 이렇게 써야겠습니다.
혹시 이 글을 보시고 더 좋은 방법을 알고 계신분은 댓글로 알려주시면 감사드리겠습니다.
2010/10/10 22:42 2010/10/10 22:42

글 걸기 주소 : 이 글에는 트랙백을 보낼 수 없습니다

덧글을 달아 주세요

  1. TTF 2010/10/11 00:28 고유주소 고치기 답하기

    http://ikpil.com/604 최익필님 블로그에서 동일한 내용을 찾았습니다.
    연관된 링크 아시면 올려주세요. ^^

  2. ohyecloudy 2010/10/11 06:05 고유주소 고치기 답하기

    http://groups.google.co.kr/group/comp.lang.c++.moderated/msg/aad7ccfb47ce0978?pli=1
    글에서 copy_if()에 대한 비야네 아저씨 답변을 볼 수 있습니다.

    저도 관련 글을 썼는데, 링크를 남겨 놓을께요.
    http://ohyecloudy.com/pnotes/archives/308

    • TTF 2010/10/11 10:27 고유주소 고치기

      역시 링크를 눌러보는 순간 신세계를 경험했습니다.
      댓글 달아 주셔서 감사드립니다.

  3. TTF 2010/11/19 21:55 고유주소 고치기 답하기

    C++0x vs2010에서는 std::copy_if가 포함되어 있습니다.
    대세는 vs2010인가 보네요. ㅎㅎ