홀짝도 구분 못하는 STL

다툴래? 나와 갈등을 빚어볼래? 급의 제목인거 같지만[..] 여튼 오늘 심심해서 코딩해보다가 다시금 STL(Standard Template Library) 에 조금 실망하게 되는 점(?)이 있어서 글을 써봅니다. 우선 평상시에는 boost 를 거의 상용하기 때문에 이런 불편함을 못느꼈었는데 STL 만 사용하는 경우 가끔씩 이런 불편함을 느끼게 되네요.

사건의 발단(?)은 오늘 누군가 인터넷 게시판에 “정수 10개를 입력 받아서 홀수와 짝수를 구분하여 각각 출력”하는 문제의 소스 코드를 디버깅 해달라고 올린걸 본 것부터였습니다. 간단한 문제니까 한번 C++ 의 표준 라이브러리와 STL 가지고 짜볼까? 하는 생각이 들어서 짜보게 되었는데 그게 재앙의 시작일 줄은 그때는 미처 몰랐습니다[..]

평소에 주로 SGI 의 STL 문서를 보기 때문에 당연히 입력은 copy_n 으로 받고 홀짝 구분은 partition 과 compose1, bind2nd, equal_to, modulus 로 만들 생각이었습니다.

자, 문제 조건이 정수 10 개를 입력받는 거니까. 우선 정수 10 개를 입력 받아서 벡터로 복사해볼까?

vector<int> input;
copy_n(istream_iterator<int>(cin), 10, back_inserter(input));

… 컴파일 중 …

어라? 컴파일이 되지 않습니다?!

다시 copy_n 문서를 자세히 보니

… This function is an SGI extension; it is not part of the C++ standard.

아하. 그렇구나. 그럼 뭐 다른 표준 함수들로 같은 기능을 구현할 수 있으려나? 하고 쭈욱 스크롤을 해보니 끝부분에 …

[1] Copy_n is almost, but not quite, redundant. If first is an input iterator, as opposed to a forward iterator, then the copy_n operation can’t be expressed in terms of copy.

… 그래, 될리가 없지. 괜히 copy_n 이 먼저 머릿속에 떠오른게 아니라고.

음 … 그러면 숫자는 정해진 갯수가 아니라 그냥 n 개를 받도록 하고 나머지 부분을 구현해볼까. 표준 라이브러리만 사용해서 이렇게 간단한 것도 구현 못할리는 없겠지! 그럼 홀짝을 구분해서 출력하기 위해서 입력받은 정수들의 벡터를 홀짝을 판별해서 좌우로 partition 을 해볼까?

vector<int>::iterator mid = partition(input.begin(), input.end(), compose1(bind2nd(equal_to<int>(), 1), bind2nd(modulus<int>(), 2)));

… 컴파일 중 …

… 또 컴파일이 안된다. 이번에는 뭐가 문제인가 하고 보니 compose1 이 없다고 하네? 설마 이것도?!

네, 역시 SGI extension 이었습니다.

그럼 뭐 어쩌란거야. 벡터에 있는 애들을 각각 n 으로 나눈 나머지를 다시 대입하거나 출력하는 것밖에 못하는 거야?; equal_to, not_equal_to, less, greater, … 이런 비교는 대체 왜 만들어둔거지. 실제 코드를 짤 때, 단순 변수 비교만으로 끝나는 부분들이 몇군데나 된다고 … :(

그렇게 해서 약 두세번의 컴파일 에러를 겪고 나오게 된 최종적인 소스 코드는 아래와 같았습니다.

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

using namespace std;

struct odd : public unary_function<int, bool>
{
    bool operator() (int x) { return (x % 2) != 0; }
};

int main()
{
    cout << "input numbers." << endl;
    vector<int> input;
    copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(input));
    vector<int>::iterator mid = partition(input.begin(), input.end(), odd());
    cout << "odd : ";
    copy(input.begin(), mid, ostream_iterator<int>(cout, " "));
    cout << endl << "even : ";
    copy(mid, input.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
}

(참고로 조금 더 예쁜 출력을 원하다면 partition 을 stable_partition 으로 바꿔도 됩니다.)

… 그저 눈물이 앞을 가리네요[..] C++ TR1 에는 boost 의 bind 라이브러리가 포함되고, boost::bind 같은 경우 compose 기능이 기본적으로 포함이기 때문에 앞으로 위와 같이 이미 만들어져 있는 함수 객체들을 쓰지 못하는 삽스러운 문제들은 없어질 거 같습니다. 하지만 앞으로도 정해진 갯수의 입력을 받을 때는 for 문을 돌리는 수 밖에 없을거 같네요. :(

Bookmark and Share
Creative Commons License
This work, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.0 Korea License.

관련된 포스트들

Tags: , , ,

  1. 飛烏’s avatar

    홀짝 구분하는 프로그램이 저렇게 아름다울[?] 수도 있구나..;

    Reply

  2. J.Strane’s avatar

    비오// STL 만 써서 모양은 안습입니다[..] boost 를 쓴다면 좀 예쁘게 될듯 …

    Reply

  3. 디지츠’s avatar

    http://cplusplus.com/ref
    쪽을 참고하시면 지원되는 표준만 볼 수 있습니다. [...]

    전 더 이상 이쁘게 STL 코드를 짜는 것은 포기했습니다.
    사람들에게 이해시키기도 힘들 뿐더러
    그걸 생각해 내는게 너무 오래 걸리더군요.

    C#을 요새 짜고 있다보니
    C#이나 자바에서 지원하는 foreach()나 for( : ) 구문들이 더 맘에 듭니다. 하하.
    다만.. C++의 Stream만은..
    이상하게 따라올 언어가 없는 거 같아요.

    Reply

  4. Trackback from Strange Blog on 2008/01/26 at 16:42

  5. J.Strane’s avatar

    디지츠// 리플과 관련하여 제 생각을 새로 포스팅 했습니다.

    Reply