C++

std::variant

developer-tj 2023. 4. 6. 12:00
반응형

std::variant는 C++17에서 추가된 표준 라이브러리 클래스로, 여러 타입 중 하나를 저장할 수 있는 유연한 클래스입니다.
이전에는 유사한 기능을 하는 std::any를 사용해왔으나, std::variant는 더욱 타입 안전하고 간결하게 사용할 수 있습니다.
std::variant는 일반적으로 union과 비슷한 방식으로 작동합니다. 즉, 저장된 값은 선택한 타입의 크기와 정렬 요구 사항을 따릅니다.

std::variant는 다음과 같은 특징을 갖습니다.
- 여러 타입 중 하나를 저장할 수 있는 유연한 클래스
- 저장된 값은 선택한 타입의 크기와 정렬 요구 사항을 따름
- 선언할 때 모든 가능한 타입을 정의해야 하며, 선언 후에는 해당 타입들 중 하나의 값만 저장할 수 있음
- switch문과 함께 사용할 수 있는 visit 함수를 제공하여, 저장된 값의 타입에 따라 다른 작업을 수행할 수 있음
- 참조, 배열 또는 void 타입은 보유할 수 없음
- 동일한 타입을 한 번 이상 보유하고, 동일한 타입의 다르게 cv-qualified 된 버전을 보유할 수 있음

std::variant는 다음과 같이 선언할 수 있습니다.

std::variant<int, double, std::string> v;


위 코드는 int, double, std::string 중 하나를 저장할 수 있는 std::variant를 선언하는 것입니다.
선언 후에는 v에 int, double, std::string 중 하나의 값을 저장할 수 있습니다.

std::variant의 값을 가져오기 위해서는 std::get 함수를 사용할 수 있습니다.

std::variant<int, double, std::string> v;
v = 42;
int i = std::get<int>(v); // v에 저장된 int 값을 가져옴

위 코드는 v에 int 값 42를 저장하고, std::get<int>(v)를 사용하여 v에 저장된 int 값을 가져오는 것입니다.

std::variant를 switch문과 함께 사용하려면, visit 함수를 사용할 수 있습니다.
visit 함수는 각 타입에 대해 작업을 수행하는 함수 객체를 인수로 받습니다.

std::variant<int, double, std::string> v;
v = 3.14;

std::visit([](auto&& arg) {
    using T = std::decay_t<decltype(arg)>;
    if constexpr (std::is_same_v<T, int>) {
        std::cout << "v contains an int: " << arg << '\n';
    } else if constexpr (std::is_same_v<T, double>) {
        std::cout << "v contains a double: " << arg << '\n';
    } else if constexpr (std::is_same_v<T, std::string>) {
        std::cout << "v contains a string: " << arg << '\n';
    }
}, v);


위 코드는 v에 double 값 3.14를 저장하고, visit 함수를 사용하여 v에 저장된 값의 타입에 따라 다른 작업을 수행하는 것입니다.

 

 

다음은 서로 다른 타입의 메시지를 큐에 입력받는 샘플 코드입니다.

#include <queue>
#include <variant>
#include <string>
#include <iostream>

struct MessageA {
    int type;
    double data;
};

struct MessageB {
    int type;
    char data[20];
};

struct MessageC {
    int type;
    std::string data;
};

using Message = std::variant<MessageA, MessageB, MessageC>;

int main() {
    std::queue<Message> messageQueue;
    
    messageQueue.push(MessageA{1, 3.14});
    messageQueue.push(MessageB{2, "hello world"});
    messageQueue.push(MessageC{3, "foo bar"});
    
    while (!messageQueue.empty()) {
        const auto& message = messageQueue.front();
        
        std::visit([](const auto& msg) {
            using MsgType = std::decay_t<decltype(msg)>;
            if constexpr (std::is_same_v<MsgType, MessageA>) {
                std::cout << "MessageA received with data: " << msg.data << std::endl;
            } else if constexpr (std::is_same_v<MsgType, MessageB>) {
                std::cout << "MessageB received with data: " << msg.data << std::endl;
            } else if constexpr (std::is_same_v<MsgType, MessageC>) {
                std::cout << "MessageC received with data: " << msg.data << std::endl;
            }
        }, message);
        
        messageQueue.pop();
    }
    
    return 0;
}

'C++' 카테고리의 다른 글

클래스 멤버 함수 포인터  (0) 2023.02.15
함수 포인터  (0) 2023.02.14