std::any
개요
std::any
는 C++17부터 도입된 기능으로, 모든 타입의 값을 안전하게 저장하고 추출할 수 있는 타입 안전(type-safe) 컨테이너입니다. 특정 타입에 국한되지 않고 다양한 타입의 객체를 하나의 변수에 담아야 할 때 유용하게 사용됩니다.
C++ 버전별 주요 키워드 도입 시기
- C++17:
std::any
가 표준 라이브러리에 처음 도입되었습니다.
내용 설명
std::any
는 내부에 어떤 타입의 값이든 저장할 수 있는 클래스 템플릿입니다. void*
처럼 타입을 완전히 잃어버리는 것과 달리, std::any
는 저장된 값의 타입을 기억하고 있어 타입 안전성을 보장합니다.
주요 멤버 함수는 다음과 같습니다.
any_cast<T>()
:std::any
객체에 저장된 값을 특정 타입T
로 캐스팅하여 반환합니다. 만약 저장된 타입과T
가 일치하지 않으면std::bad_any_cast
예외를 발생시킵니다.has_value()
:std::any
객체가 값을 가지고 있는지 여부를true
/false
로 반환합니다.type()
: 저장된 값의type_info
를 반환합니다.typeid()
와 함께 사용하여 저장된 타입을 확인할 수 있습니다.reset()
: 저장된 값을 파괴하고std::any
를 비웁니다.
예제 코드
#include <any>
#include <iostream>
#include <string>
#include <typeinfo>
// std::string_literals 네임스페이스를 사용하여 "..."s 형태의 문자열 리터럴을 사용합니다.
using namespace std::string_literals;
// std::any 객체에 저장된 값이 정수(int)인지 확인하는 함수
bool is_integer(const std::any &a)
{
return a.type() == typeid(int);
}
// std::any 객체에 저장된 값이 문자열(std::string)인지 확인하는 함수
bool is_string(const std::any &a)
{
return a.type() == typeid(std::string);
}
int main()
{
// 1. std::any 객체 생성 및 값 할당
auto value = std::any{42}; // int 타입의 42 저장
std::cout << "Size of std::any: " << sizeof(value) << " bytes" << '\n';
value = 42.0; // double 타입의 42.0 저장
std::cout << "Size of std::any: " << sizeof(value) << " bytes" << '\n';
value = "42"s; // std::string 타입의 "42" 저장
std::cout << "Size of std::any: " << sizeof(value) << " bytes" << '\n';
// 2. std::any_cast를 사용한 값 추출 (try-catch)
try
{
// 현재 value는 std::string을 담고 있으므로 성공적으로 캐스팅됩니다.
auto s = std::any_cast<std::string>(value);
std::cout << "Successfully casted to string: " << s << '\n';
}
catch (const std::bad_any_cast &e)
{
std::cout << e.what() << '\n';
}
// 3. 타입 확인
std::cout << "is_integer: " << std::boolalpha << is_integer(value) << '\n';
std::cout << "is_string: " << std::boolalpha << is_string(value) << '\n';
// 4. 값 존재 여부 확인
std::cout << "has_value: " << std::boolalpha << value.has_value() << '\n';
// 5. 포인터를 사용한 안전한 캐스팅 (예외를 발생시키지 않음)
// 실패 시 nullptr을 반환합니다.
int* int_ptr = std::any_cast<int>(&value);
std::cout << "Casting to int*: " << (int_ptr ? "success" : "failed (returns nullptr)") << '\n';
std::string* string_ptr = std::any_cast<std::string>(&value);
std::cout << "Casting to string*: " << (string_ptr ? "success" : "failed (returns nullptr)") << '\n';
if (string_ptr)
{
std::cout << "Value from pointer cast: " << *string_ptr << '\n';
}
// 6. 값 리셋
value.reset();
std::cout << "After reset, has_value: " << std::boolalpha << value.has_value() << '\n';
return 0;
}
실행 결과
Size of std::any: 64 bytes
Size of std::any: 64 bytes
Size of std::any: 64 bytes
Successfully casted to string: 42
is_integer: false
is_string: true
has_value: true
Casting to int*: failed (returns nullptr)
Casting to string*: success
Value from pointer cast: 42
After reset, has_value: false
참고: sizeof(std::any)
의 크기는 컴파일러와 아키텍처에 따라 다를 수 있습니다.
활용팁
std::variant
와의 비교: 저장할 타입의 종류가 컴파일 타임에 알려진 제한된 집합이라면std::variant
를 사용하는 것이 더 효율적이고 안전합니다.std::any
는 저장될 타입을 전혀 예측할 수 없는 경우에 사용하세요.- 예외 없는 캐스팅:
std::any_cast
는 잘못된 타입으로 캐스팅 시 예외를 던집니다. 예외 처리가 부담스럽다면std::any_cast<T>(&any_object)
처럼 포인터 형태로 캐스팅을 시도할 수 있습니다. 이 경우 캐스팅에 실패하면nullptr
를 반환하므로, 반환된 포인터를 확인하여 안전하게 값을 사용할 수 있습니다. - 성능 고려:
std::any
는 작은 객체는 내부에 직접 저장(Small Object Optimization)하지만, 일정 크기 이상의 객체는 동적 할당을 사용합니다. 이로 인해 힙 할당 및 가상 함수 호출에 따른 약간의 성능 저하가 발생할 수 있으므로, 성능이 매우 중요한 코드에서는 사용에 주의가 필요합니다.
'개발 > C++ (98,03,11,14,17,20,23)' 카테고리의 다른 글
Modern C++ : std::variant (17) (0) | 2025.09.29 |
---|---|
Modern C++ : std::optional (17) (0) | 2025.09.28 |
Modern C++ : Type Traits 2 (11, 14, 17, 20) (0) | 2025.09.27 |
Modern C++ : Variadic Templates and Fold Expressions (11, 17) (0) | 2025.09.26 |
Modern C++ : std::concepts (20) (0) | 2025.09.25 |
Modern C++ : Type Traits 1 (11, 14, 17, 20) (0) | 2025.09.24 |
Modern C++ : 템플릿 특수화 (Template Specialization) (98, 11, 17) (0) | 2025.09.23 |
Modern C++ : 복사 및 이동 의미론 (Copy and Move Semantics) (98, 11) (0) | 2025.09.22 |