Menu
CoddyTech

optional, variant, any

Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 104개 중 89번째.

Modern C++는 <optional>, <variant>, <any> 헤더에서 값이 없을 수도 있거나, 여러 타입 중 하나를 보유하거나, 어떤 타입이든 저장할 수 있는 값을 처리하는 데 도움이 되는 세 가지 어휘 타입을 제공합니다.

std::optional<T>은 존재할 수도 있고 존재하지 않을 수도 있는 값을 나타냅니다. 예외를 발생시키지 않고 실패할 수 있는 함수에 적합합니다:

#include <iostream>
#include <optional>
std::optional<int> findIndex(const std::string& str, char c) {
    for (size_t i = 0; i < str.size(); ++i) {
        if (str[i] == c) return i;
    }
    return std::nullopt;  // 값 없음
}
int main() {
    auto result = findIndex("hello", 'l');
    if (result.has_value()) {
        std::cout << "Found at: " << *result << "\n";  // 2
    }
}

std::variant<Types...>는 지정된 타입 중 정확히 하나를 언제든 보유하는 타입 안전 유니온입니다:

#include <iostream>
#include <variant>
#include <string>
int main() {
    std::variant<int, double, std::string> data;
    data = 42;
    std::cout << std::get<int>(data) << "\n";
    data = "hello";
    if (std::holds_alternative<std::string>(data)) {
        std::cout << std::get<std::string>(data) << "\n";
    }
}

std::any는 런타임에 결정되는 모든 유형의 값을 보유할 수 있습니다. 값을 가져오려면 std::any_cast를 사용하세요.

#include <iostream>
#include <any>
int main() {
    std::any value = 10;
    std::cout << std::any_cast<int>(value) << "\n";
    value = std::string("text");
    std::cout << std::any_cast<std::string>(value) << "\n";
}

null이 될 수 있는 값에는 std::optional을 선택하고, 컴파일 시점에 가능한 타입을 알고 있다면 std::variant를 사용하며, 런타임 타입 유연성이 정말 필요할 때만 std::any를 사용하세요.

challenge icon

챌린지

쉬움

현대 C++ 어휘 타입의 강력한 기능을 보여 주는 구성 시스템을 만들어 보겠습니다. 값이 없을 수도 있고, 다양한 타입을 저장할 수도 있으며, 런타임에 타입을 유연하게 처리해야 하는 설정 관리자를 만들게 됩니다.

코드를 세 개의 파일로 구성합니다:

  • ConfigTypes.h: 구성 값 타입과 도우미 함수를 정의합니다.

    문자열을 받아 정수로 파싱을 시도하는 parseValue 함수를 만드세요. 문자열이 유효한 정수를 나타내면 정수를 std::optional로 감싸서 반환합니다. 파싱에 실패하면(문자열에 숫자가 아닌 문자가 포함된 경우) std::nullopt를 반환합니다. 간단하게 하기 위해 문자열에 숫자만 포함되어 있거나 앞에 선택적으로 마이너스 기호가 포함되어 있으면 유효한 문자열로 간주하세요.

    int, double, std::string 중 하나를 저장할 수 있는 std::variant를 사용하여 Setting이라는 타입 별칭도 만드세요.

    마지막으로 Setting을 받아 어떤 타입을 저장하고 있는지와 그 값을 다음 형식의 문자열로 설명하여 반환하는 describeSetting 함수를 만드세요:

    • int인 경우: Integer: [value]
    • double인 경우: Double: [value]
    • string인 경우: String: [value]
  • DynamicStore.h: std::any를 사용하여 간단한 키-값 저장소를 만드세요.

    모든 타입의 값을 저장할 수 있는 DynamicStore 클래스를 정의하세요. 다음 항목을 포함해야 합니다:

    • 문자열 키와 std::any 값을 받아 내부에 저장하는 set 메서드(std::map을 사용하세요)
    • 키를 받아 std::any 값을 반환하는 get 메서드(키가 존재하지 않으면 빈 std::any를 반환합니다)
    • 키가 존재하면 true를 반환하는 hasKey 메서드
  • main.cpp: 세 개의 입력을 읽습니다:
    1. 숫자일 수도 있는 문자열(std::optional 테스트용)
    2. 타입 표시자: int, double 또는 string
    3. 해당 타입에 맞는 값

    세 가지 어휘 타입을 모두 시연하세요:

    먼저 첫 번째 입력에 parseValue 함수를 사용하세요. 값이 포함되어 있으면 Parsed: [value]를 출력합니다. 비어 있으면 Parse failed를 출력합니다.

    두 번째로 타입 표시자에 따라 Setting variant를 만드세요. 타입이 int이면 값을 정수로 저장합니다. double이면 double로 저장합니다. string이면 문자열로 저장합니다. 그런 다음 describeSetting을 호출하고 결과를 출력하세요.

    세 번째로 DynamicStore를 만들고, 키 "status" 아래에 문자열 "config_loaded"를 저장한 다음 이를 검색하여 Status: [value]를 출력하세요. 값을 추출하려면 std::any_cast<std::string>을 사용하세요.

예를 들어 입력이 42, int, 100인 경우:

Parsed: 42
Integer: 100
Status: config_loaded

입력이 hello, double, 3.14인 경우:

Parse failed
Double: 3.14
Status: config_loaded

입력이 -15, string, username인 경우:

Parsed: -15
String: username
Status: config_loaded

필요한 곳에 적절한 헤더인 <optional>, <variant>, <any>, <string>, <map>을 포함해야 합니다. variant를 다루려면 std::holds_alternative와 std::get을 사용하고, optional을 확인하려면 has_value() 또는 직접적인 불리언 변환을 사용하세요.

직접 해보기

#include <iostream>
#include <string>
#include <any>
#include "ConfigTypes.h"
#include "DynamicStore.h"

int main() {
    // 세 개의 입력을 읽기
    std::string input1;  // 숫자일 수 있는 문자열 (std::optional 테스트용)
    std::string typeIndicator;  // 타입 표시자: int, double 또는 string
    std::string value;  // 해당 타입에 대응하는 값
    
    std::cin >> input1;
    std::cin >> typeIndicator;
    std::cin >> value;
    
    // TODO: Part 1 - parseValue로 std::optional 테스트
    // input1과 함께 parseValue 함수 사용
    // 값이 포함되어 있으면 "Parsed: [value]" 출력
    // If it's empty, print "Parse failed"
    
    
    // TODO: Part 2 - Setting으로 std::variant 테스트
    // typeIndicator를 기반으로 Setting variant 생성
    // 타입이 "int"이면 value를 정수로 저장
    // 타입이 "double"이면 value를 double로 저장
    // 타입이 "string"이면 value를 문자열로 저장
    // 그런 다음 describeSetting을 호출하고 결과를 출력합니다
    
    
    // TODO: Part 3 - DynamicStore로 std::any 테스트
    // DynamicStore 생성
    // 키 "status" 아래에 문자열 "config_loaded"를 저장
    // 이를 가져와 출력: "Status: [value]"
    // 값을 추출하려면 std::any_cast<std::string>을 사용
    
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 C++ 컴파일러