boost::any
C#, JAVA와 같이 모든 타입을 지칭할 수있는 타입을 제공한다.
필요 헤더
#include <boost/any.hpp>
모든 타입을 담을 수 있는 클래스
void example2()
{
boost::any variable(std::string("Hello World!"));
// if casting failed, may throw boost::bad_any_cast
string s1 = boost::any_cast<string>(variable);
// if casting failed, s2 is null
string* s2 = boost::any_cast<string>(&variable);
}
값에 대한 any_cast는 타입이 맞지 않을 시 boost::bad_any_cast를 던진다.
포인터에 대한 any_cast는 null로 대체 된다.
내부에 같은 타입으로 포인터를 두고 있으며
생성할 때 ValueType을 담도록 동적 할당한 다음 값을 복사하여 placeholder가 가지고 있도록 한다.
C++17에 정식으로 채택됐다.
RTTI 정보를 사용하므로 성능상 비용이 존재한다.
복사 생성, 값 생성, 복사 할당, 값 할당 시 동적 메모리 할당을 요구한다.
#include <boost/any.hpp>
using std::string;
using std::vector;
class BoostAny
{
public:
static void example()
{
struct MyType
{
int val;
};
vector<boost::any> untyped_container;
untyped_container.push_back(1);
untyped_container.push_back(10.5f);
untyped_container.push_back('w');
untyped_container.push_back("value");
untyped_container.push_back(MyType{ 10 });
for (const auto& v : untyped_container)
{
if (auto p = boost::any_cast<int>(&v))
{
cout << "int: " << *p << endl;
}
else if (auto p = boost::any_cast<float>(&v))
{
cout << "float: " << *p << endl;
}
else if (auto p = boost::any_cast<char>(&v))
{
cout << "char: " << *p << endl;
}
else if (auto p = boost::any_cast<const char*>(&v))
{
cout << "string: " << *p << endl;
}
else if (auto p = boost::any_cast<MyType>(&v))
{
cout << "MyType: " << p->val << endl;
}
}
}
boost::variant
#include <boost/variant.hpp>
boost::any의 경우 동적 할당과 RTTI 정보를 사용하므로 동적 코스트가 존재한다. 이에 boost::variant는 컨테이너에 여러 타입을 컴파일 시간에 결정해주고 동적 코스트 없이 사용할 수 있게 해준다.
boost::variant에 사용할 타입을 지정하여 컨테이너를 정의하면 여러 타입을 컨테이너에 담을 수 있다.
static void p_example()
{
using my_var_t = boost::variant<int, const char*, string>;
vector<my_var_t> some_values;
some_values.push_back(10);
some_values.push_back("Hello there!");
some_values.push_back(std::string("Wow!"));
string& s = boost::get<string>(some_values.back());
s += "That is great!\n";
cout << s;
}
특징
- variant에는 boost::blank 타입이 있는데 빈 상태를 표현한다.
- variant도 값 타입에 get을 한다면 boost::bad_get 예외를 던지나 포인터 타입에는 null을 반환하도록 한다.
- variant 변수의 which()를 호출하면 정의한 타입의 인덱스를 반환한다.
- C++17에 정식으로 도입되었다.
static void p_example2()
{
using my_var_t = boost::variant<boost::blank, int, const char*, string>;
my_var_t var;
// variant가 소유한 형식의 인덱스를 반환
assert(var.which() == 0);
var = "Hello, dear reader";
assert(var.which() != 0);
my_var_t var2(0);
// int가 아니라면 boost::bad_get 예외를 던진다.
int s1 = boost::get<int>(var2);
// int가 아니라면 null을 반환
int* s2 = boost::get<int>(&var2);
}
방문자 패턴을 이용한 variant 활용
variant 타입을 이용하여 동적 타입 확인 없이 컨테이너를 순회하며 각 원소에 대해 타입에 따라 다른 작업을 요할 때 적용할 수 있다.
여러 타입의 필드를 갖는 db row를 타입에 맞춰 statement string을 만들어내는 예제
class BoostVariant
{
private:
using cell_t = boost::variant<int, float, string, time_t>;
using db_row_t = vector<cell_t>;
template<size_t sz>
struct statement_visitor : public boost::static_visitor<void> {
size_t i = 0;
std::stringstream& _ss;
statement_visitor(std::stringstream& ss) : _ss(ss) {}
void append_comma() {
if (++i != sz)
_ss << ", ";
}
void operator()(int value) {
_ss << value;
append_comma();
}
void operator()(float value) {
_ss << value;
append_comma();
}
void operator()(const std::string& s) {
_ss << s;
append_comma();
}
void operator()(const time_t& t) {
struct tm tms;
gmtime_s(&tms, &t);
char buf[64];
snprintf(buf, 64, "%4d-%02d-%02d %02d:%02d:%02d", tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday, tms.tm_hour, tms.tm_hour, tms.tm_sec);
_ss << buf;
append_comma();
}
};
static std::string make_insert_statment(const db_row_t& row)
{
std::stringstream ss;
statement_visitor<4> v(ss);
ss << "INSERT INTO mytable VALUES(";
for (int i = 0, cnt = row.size(); i < cnt; ++i) {
boost::apply_visitor(v, row[i]);
}
ss << ")" << endl;
return ss.str();
}
public:
static void example()
{
db_row_t row;
row.push_back(0);
row.push_back(1.0f);
row.push_back(string("aaa"));
row.push_back(time(NULL));
string st = make_insert_statment(row);
cout << "statement is " << st << endl;
}
};
boost::optional
값이 존재하지 않은 상태를 표현. 동적 할당없이 값을 내부에 저장한다.
#include <boost/optional.hpp>
예시
#pragma once
#include "global.h"
#include <boost/optional.hpp>
class BoostOptional
{
public:
static void example()
{
using OptinalInt = boost::optional<int>;
OptinalInt val;
if (!val.has_value())
{
cout << "no value" << endl;
}
if (!val.is_initialized())
{
cout << "not initialied" << endl;
}
val.emplace(10);
cout << "value : " << val.get() << " has value : " << val.has_value() << " initialized : " << val.is_initialized() << endl;
}
};
'C++ > Boost' 카테고리의 다른 글
[Boost] 문자열 다루기 (0) | 2022.08.21 |
---|---|
[Boost] thread (0) | 2022.08.21 |
[Boost] program_options (0) | 2022.08.20 |
[Boost] 라이브러리 설치 (0) | 2022.08.20 |