C++17 표준 라이브러리의 std::any 소개

Twitter icon류광, 2017-07-08 19:07
C++17 표준 라이브러리에 추가된 std::any를 소개합니다.

다음은 6월에 출간된 "핵심 C++ 표준 라이브러리"의 부록 A의 일부입니다. 원래는 블로그 글을 먼저 쓰고 그걸 다듬어서 부록으로 수록하려 했는데(stringview 소개글optional 소개글이 그런 시도의 결과입니다) 책이 먼저 나와버렸습니다.

어쨌거나, 핵심 C++ 표준 라이브러리 번역서 출간과 연계해서 이 블로그에서 C++17 표준 라이브러리를 소개한다는 애초의 계획을 실행하기 위해 부록의 나머지 부분을 이곳에 차츰 올리도록 하겠습니다. 첫 타자는 std::any입니다. 블로그 말투가 아니라 단행본 문체라 좀 어색할 수도 있지만, 그냥 그대로 갑니다!

아무 형식이나 담을 수 있는 std::any

std::any 형식의 객체에는 말 그대로 ‘아무(any)’ 형식의 값을 담을 수 있다. 단, 복사가 가능한(copyable) 형식이어야 한다. 필요한 헤더는 <any>이다.

struct Position { double x, y, z; };

void f()
{
   any a = std::string("C++ 문자열");

   a = 123;                // 새 값이 배정되기 전에 기존 값(string 객체)이
                           // 파괴된다(소멸자 호출 및 메모리 해제).

   a = Position{1, 2, 3};  // 복사할 수 있는 형식이면 어떤 형식도 가능.
}

이런 식으로 한 변수에 임의의 형식의 값을 담아야 할 때 흔히 쓰이는 수단은 무형식 포인터(typeless pointer) void*reinterpret_cast(또는 C 스타일 캐스팅)이다. 그러나 그 둘만으로는 형식 안전성을 보장하기 힘들다. 형식 안전성을 위해서는 any 객체에 새 값이 배정되기 전에 기존 값이 제대로 파괴되어야 하는데, void*만으로는 그것을 보장하기 힘들다. 그러나 앞의 예제의 주석에서 보듯이 any는 객체의 적절한 파괴(소멸)를 보장한다. 이런 측면 때문에 std::any를 “형식에 안전한(typesafe) void*”라고 표현하기도 한다.

any 객체에 담긴 값을 꺼낼 때는 std::any_cast라는 함수를 사용한다.

any a = string("C++ 문자열");

cout << any_cast<string>(a) << endl // C 문자열

int i = any_cast<int>(a);           // 형식이 일치하지 않음:
                                    // bad_any_cast 예외 발생.

위의 예처럼 any 객체 자체를 인수로 받는 any_cast는 만일 요청된 형식과 자신에 담긴 자료의 형식이 일치하지 않으면 std::bad_any_cast 형식의 예외를 던진다. 이러한 형식 점검은 std::any를 “형식에 안전한 void*”라고 부르는 또 다른 이유이다.

형식이 일치하지 않을 때 예외가 발생하는 것을 원하지 않는다면, 다음처럼 포인터를 받고 포인터를 돌려주는 버전의 any_cast를 호출하면 된다. 이 버전은 형식이 일치하지 않으면 널 포인터(nullptr)를 돌려준다.

optional처럼 any에도 빈 객체를 생성하는 기본 생성자가 있으며, 멤버 함수 has_value, emplace, reset도 있다. any의 멤버 함수 typeany 객체에 담긴 자료의 형식을 나타내는 type_info 객체(에 대한 참조)를 돌려준다. 빈 any 객체의 경우 그 type_info 객체는 typeid(void)에 해당한다.

any a;                              // 빈 객체

cout << a.has_value() << endl;      // false

a.emplace<string>("Hello, world!"); // 제자리 생성.

cout << a.type().name << endl;      // 구체적인 형식 이름은 
                                    // 컴파일러마다 다를 수 있음.

opt2.reset();                       // 이제 has_value()는 false.
태그: C++ C++17 표준 라이브러리

comments powered by Disqus