지난 3월에 C++ Standard Committee회의가 독일 베를린에서 있었다는군요. 이거 엄청난 뒷북이겠으나, 괄목할만한 것들이 들어있기에 언급하고 넘어가려고 합니다. (대체 이게 얼마만의 Development Note냐.. 반성좀 하자.)
일단, 소스는 Dr. Dobb’s Journal의 C++ Department (formerly C/C++ User’s Journal) 6월호(?)에 실린 Pete Becker씨의 Living by the Rules: Part II입니다. Pete Becker씨의 글은 참 읽기 편하고 즐거워요. 🙂 C++ Standard Committee 멤버이고, C++ Standard의 Project Editor로 계신답니다. 지금 C++ Library Standard TR1에 대한 책을 쓰고 계시다는군요. 기대중.
0. 일단, 보통 하던 실수들이 에러가 아니게 됩니다!!!
예를 들면,
std::vector<std::pair<int,int>> vect;
와 같은 코드는 타입끝에 있는 >>가 shift-right 연산자로 인식되기 때문에 컴파일이 되면 안되고 사이에 공백문자 하나를 끼워 넣어줘야 제대로 되었었지요. 실제로 KLDP에 종종 올라오던 질문이 저거였습니다만, 이제 저렇게 써도 컴파일이 되도록 표준이 바뀐답니다. 막상 저는 습관적으로 space하나를 넣을지도…
template <class T> class no_children { no_children(){} friend class T; } class final : virtual no_children<final> { /*...*/ } class illegal_final : public final { /*....*/ }
와 같은 코드는 작동한다면, final클래스를 상속받을 수 없는 클래스가 됩니다. illegal_final때문에 컴파일이 되지 않는 것이지요. 이유는 virtual키워드에 있습니다. virtual 키워드가 없다면 illegal_final 클래스는 생성시에 final class의 생성자를 통해서 no_children의 생성자를 호출하기 때문에 문제가 발생하지 않습니다만, virtual키워드가 있다면 final class의 생성자가 아니라 자신이 no_children의 생성자를 호출해야합니다. virtual키워드에 대해서는 따로 다루도록 해보지요.
어쨌든, Java에 존재하는 final이라는 키워드가 구현이 된다는 것인데, 막상 illegal_final을 제외해도 컴파일이 되지 않습니다. C++에서 friend에 사용되는 클래스는 완성되어 있어야하는데, final 클래스가 아직 완성되지 않은 시점에 template argument로 넘겨줬기 때문에 no_children 클래스에서 friend 선언이 제대로 먹히지 않기 때문입니다. 이게 가능하게 바뀌었다는군요. friend 선언에서 더 넓은 범위의 문법적 요소들을 friend 선언에서 쓸 수 있게 바꿨답니다. (즉슨, 문법적으로 맞다면 상관 없음! 인듯 하군요)
struct S { S() : i(0), j(0){} S(int j0) { S(); // 실수!! j = j0; } int i, j; }
위 예제도 많이하는 실수중 하나인데, 원래 하려고 했던건 S의 기본 생성자를 호출하고 싶었던 겁니다. S(); 부분은 S의 임시객체를 생성하기 때문에 전혀 S의 생성에 영향을 주지 못합니다. -_- 이것때문에 Initialize라는 별도의 멤버함수로 뽑아서 사용했던 기억이 문득 나는군요. 이제 아래와 같은 형태가 가능해진답니다.
struct S { S() : i(0), j(0){} S(int j0) : S() // 바뀐 곳! { j = j0; } int i, j; }
원래는 생성자 뒤에 생성목록을 써줄때, 자기자신의 다른 생성자는 호출이 안되었었는데 이게 되는걸로 바뀐답니다. 좋군요. 후후.
1. 이 외에 문법적인 변경중, 제일 좋은건.. auto의 도입(혹은 변경)입니다!!!
기존에는 아래와 같이 썼었죠.
for(std::vector<int>::iterator itr = v.begin(); itr != v.end(); ++itr) { std::cout << *itr << std::endl; } [/cpp] 이게, 이렇게 해도 된답니다. [cpp] for(auto itr = v.begin(); itr != v.end(); ++itr) { std::cout << *itr << std::endl; } [/cpp] 만세- 설명을 드리자면, auto는 원래 자동변수라고 해서 생략해도 다 자동변수이기 때문에 아무도 안쓰는 키워드였습니다. 그걸, 컴파일러가 맞는 타입을 찾아서 자동으로 타입을 지정해주는 일종의 자동타입이랄까요? 이 경우는 v.begin()리턴이 적합한 type이니 std::vector::iterator가 자동으로 type이 됩니다. 하하. 만세- 만세- <strong>2. 공유라이브러리와 템플릿</strong> 그리고, 다음은.. <strong>공유라이브러리와 템플릿에 관련된 문제</strong>이네요. 템플릿은 특성상 쓰여진 곳에서 코드를 전개해 만드는 방식이라는 것은 알고 계시리라 생각됩니다. 이게, 공유라이브러리에 전개된 코드를 다 때려박고 싶을때 사용할 키워드가 없어서, 주로 컴파일러에서 제공하는 특정기능을 썼었는데... 이게 가능하도록 바뀌었답니다. 요는 extern키워드군요. [cpp] std::basic_string<char> str;
위 코드를 실행파일에서 가져다 쓰는 코드라고 가정합시다. 원칙대로라면, 지금 std::basic_string의 컴파일된 코드는 실행파일 바이너리에 들어가있게 됩니다. 보통은 에 이렇게 정의되어 있기 때문이지요.
// 에 들어있을 겁니다.. 아마도. template <> basic_string<char>;
앞으로는 이렇게 하는게 가능해 진답니다.
extern template<> basic_string<char>;
extern 키워드가 붙게되면, basic_string에 대한 바이너리 코드들을 컴파일할때 생성하려고 하는게 아니라, 링크타임에 찾게 됩니다. 즉, DLL에 basic_string를 집어넣을 수 있다는 이야기이지요. 기존의 STL라이브러리들이 이걸 하려고 컴파일러에서 제공하는 확장기능을 사용해 왔었는데, 표준으로 확정이 된다는 말입니다. 실제 프로그래머들은 쓸일이 없다고 생각하실수도 있겠지만, 아마도 유용할때가 있을 듯 합니다.
3. Standard Library쪽에도 변경이 가해졌습니다.
일단, 최소값과 최대값을 한번에 찾는 minmax/minmax_element 알고리즘이 추가되었군요. 이제 min, max를 따로 돌리느라 2*n의 복잡도를 가질 필요가 없어졌습니다. 하하.
그리고, char*만 받아들이던 함수들에 전부 std::string을 받는 오버로딩이 추가됩니다. 이런거죠.
std::string filename("aaa.txt"); std::ofstream old_file(filename.c_str()); // 기존 코드 std::ofstream new_file(filename); // 변경되는 표준에서 되는 코드
그리고, vector같은 데서 컨테이너가 const_iterator를 얻는 멤버함수인 cbegin(), cend(), crbegin(), crend()가 추가된답니다. 더 이상 const_iterator를 얻느라 캐스팅을 하지 않아도 되는군요. 만세-
이 외에도 Floating-point관련 개선과 C99호환성 부분이 있군요. 특기할만한 점이란… 매크로에 가변 변수를 쓸 수 있답니다.
#define debug(...) fprintf(stderr, __VA_ARGS__)
상당히 편할듯 합니다.
4. 끝으로
이렇게 편해지는건 좋은데, 언제쯤 구현이 되어서 쓸 수 있게 될지… 회사에서는 Visual Studio 2003/2005를 쓰기 때문에.. 설마 VS다음버젼을 기다려야 하는거면.. OTL
GCC에서는 금방해주겠죠.. 으흐.
개인적으로는 auto가 정말 만세입니다-
good! enhancements in C++ are very impressive..
auto 키워드의 저런 용법은 원래 ML이나 Haskell 같은 함수형 언어에서 자료형을 지정할 때 사용하는 방법이지. C++은 정말 multi-paradigm language가 되어 가는군. 근데, auto 설명하는 데 있는 예제 코드는 그냥 copy(v.begin(), v.end(), ostream_iterator(cout, “n”)); 하면 되지 않나.. ㅎㅎ
Richard K//
But, there are more issues to improve C++. See TR2
귤//
나도 알고리즘을 주로 쓰기 때문에, 형식삭제는 즐겨 쓰는 스킬이지.
허나… 많은 사람들이 저리 짜고 있고, auto가 도입될때 오옷. 하고 느낄만한 예제는 저거. ㅎㅎ
회사에서 일하다 보면 알고리즘을 안쓰는 사람들이 상당히 많으심. ;ㅁ;
요즘은 MFC를 보면, 흑백영화를 보는 기분.. -_-