http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0088r3.html
C++17은 타입-세이프 한 공용체가 필요했고, 그것을 구현했습니다.
std::variant는 union 과 똑같이 행동하지만, 타입에 안전합니다.
std::variant는 값의 수명을 유지하고 관리합니다. 만약 variant가 값을 보유하고 있는경우, 그 값의 유형은 템플릿 인수 유형중 하나여야 합니다.
주어진 시간에 variant는 객체 유형중 하나의 값을 보유하거나 보유하지 않습니다.
variant 인스턴스가 T 타입의 값을 보유하면, 이는 T 타입의 값이 variant 저장소 내에 할당됨을 의미합니다.
T 타입을 보유하기 위해 동적 메모리같은 추가 저장소를 사용하진 않습니다. 단순히 Types에 있는 모든 유형에 대해 적절히 정렬된 변형 저장소를 사용합니다.
모든 타입은 참조할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
variant<int, double, std::string> vunion = 1; // variant type = int
cout << std::get<int>(vunion) << endl; //1
vunion = 3.5; //variant type = double, int 객체는 삭제됨
cout << std::get<double>(vunion) << endl; //3.5
cout << std::get<1>(vunion) << endl; // 위와 같은 효과
auto t = std::get<double>(vunion); // t 에 값을 담음
auto i = std::get<int>(vunion); // bad_variant_access 예외를 던짐
auto str = std::get<string>(vunion); // bad_variant_access 예외를 던짐
|
값 접근을 위한 멤버, 비멤버 함수를 지원합니다.
1
2
3
4
5
6
7
8
9
|
std::variant<int, double, std::string> vunion = "abc"s;
vunion.index(); // 2
std::holds_alternative<int>(vunion); //false
std::holds_alternative<std::string>(vunion); // true
std::get_if<std::string>(&vunion); // string*
std::get_if<bool>(&vunion); // nullptr
|
index() 멤버함수는 현재 variant 의 인덱스를 반환합니다.
std::holds_alternative 비멤버함수는 variant 인스턴스를 받아 그 타입이 유효한지에 대해 bool 값을 반환합니다.
std::get_if 비멤버함수는 variant 인스턴스를 받아, 그 타입이 유효하다면 타입의 포인터형을 반환합니다.
타입이 유효하지않다면 bad_variant_access 예외를 던지는 대신, nullptr을 반환합니다.
1
2
3
4
5
6
7
8
9
|
std::variant<int, double, std::string> vunion = "abc"s;
vunion.index(); // 2
std::holds_alternative<int>(vunion); //false
std::holds_alternative<std::string>(vunion); // true
std::get_if<std::string>(&vunion); // string*
std::get_if<bool>(&vunion); // nullptr
|
std::visit 라는 비멤버 함수도 지원한다.
이 함수는 std::variant 인스턴스에 담겨있는 타입에 맞게 operator를 호출해준다.
1
2
|
template <class Visitor, class... Variants>
constexpr ReturnType visit(Visitor&& vis, Variants&&... vars);
|
std::visit는 기본적으로 방문자 패턴 ( visitor pattern ) 의 구현을 위해 사용된다.
using var_t = std::variant<int, double, std::string>;
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
int main() {
std::vector<var_t> varvec = { 10,3.5,"abc"s };
for (auto& i : varvec) {
std::visit([](auto&& args) {
cout << args << endl;
}, i);
//void visitor, 부작용만 일으킴
var_t vs = std::visit([](auto&& arg) -> var_t {
return arg + arg;
}, i);
// 값 반환 방문자, 받는 인자를 통해 새로운 타입으로 반환함
std::visit([](auto&& args) {
using T = std::decay_t<decltype(args)>;
if constexpr (std::is_same_v<T, int>)
cout << "타입 : int" << endl;
else if constexpr (std::is_same_v<T, double>)
cout << "타입 : double" << endl;
else if constexpr (std::is_same_v<T, std::string>)
cout << "타입 : std::string" << endl;
}, vs);
// 타입 매칭 방문자, 각 타입을 다르게 처리함
}
cout << "new varvec" << endl;
for (auto& i : varvec) {
std::visit(overloaded {
[](int arg) { cout << "타입 : int" << endl; },
[](double arg) { cout << "타입 : double" << endl; },
[](const std::string& arg) { cout << "타입 : std::string" << endl; }
}, i);
// 다른 타입 매칭 방문자, operator() 를 호출함
// 다중 람다를 할 수 있는 이유는 overloaded가 가변인자 템플릿이기 때문
}
}
|
cs |
'C++ > Modern' 카테고리의 다른 글
C++20) Coroutine ( 코루틴 ) - 1 (0) | 2020.08.20 |
---|---|
C++20) Designated Initializer ( 지정된 초기화 ) (0) | 2020.08.19 |
C++17) std::any (0) | 2019.02.27 |
C++17) std::optional (0) | 2019.02.27 |
C++17) std::string_view (0) | 2019.02.26 |