Namespaces
Variants

std:: visit

From cppreference.net
Utilities library
헤더에 정의됨 <variant>
template < class Visitor, class ... Variants >
constexpr /* see below */ visit ( Visitor && v, Variants && ... values ) ;
(1) (C++17부터)
template < class R, class Visitor, class ... Variants >
constexpr R visit ( Visitor && v, Variants && ... values ) ;
(2) (C++20부터)
도우미 템플릿
template < class ... Ts >
auto && as - variant ( std:: variant < Ts... > & value ) ;
(3) ( 설명 전용* )
template < class ... Ts >
auto && as - variant ( const std:: variant < Ts... > & value ) ;
(4) ( 설명 전용* )
template < class ... Ts >
auto && as - variant ( std:: variant < Ts... > && value ) ;
(5) ( 설명 전용* )
template < class ... Ts >
auto && as - variant ( const std:: variant < Ts... > && value ) ;
(6) ( 설명 전용* )

방문자 v (Variants의 타입 조합으로 호출 가능한 Callable 객체)를 Variants values 에 적용합니다.

VariantBases decltype ( as-variant ( std:: forward < Variants > ( values ) ) ... ( sizeof... ( Variants ) 개의 타입 패크)로 주어집니다:

1) v 를 다음과 같이 호출합니다

INVOKE ( std:: forward < Visitor > ( v ) ,
std :: get < indices > ( std:: forward < VariantBases > ( values ) ) ... )
,

여기서 indices as-variant ( values ) . index ( ) ... 입니다.
2) v 를 다음과 같이 호출합니다

INVOKE<R> ( std:: forward < Visitor > ( v ) ,
std :: get < indices > ( std:: forward < VariantBases > ( values ) ) ... )
,

여기서 indices as-variant ( values ) . index ( ) ... 입니다.

이 오버로드들은 VariantBases 의 모든 타입이 유효한 타입일 때만 오버로드 해결에 참여합니다. INVOKE 또는 INVOKE<R> (C++20부터) 로 표시된 표현식이 유효하지 않거나, INVOKE 또는 INVOKE<R> (C++20부터) 의 결과가 서로 다른 indices 에 대해 다른 타입이나 값 범주를 가지는 경우, 프로그램은 형식이 잘못되었습니다.

3-6) 설명 전용(exposition-only) as-variant 함수 템플릿은 해당 타입이 추론될 수 있는 값을 받아들여 std:: variant < Ts... > (즉, std:: variant < Ts... > 또는 std:: variant < Ts... > 에서 파생된 타입)에 대한 값을 반환하며, 동일한 const 한정자와 값 범주를 가진 std::variant 값을 반환합니다.
3,4) 반환 value .
5,6) 반환값 std :: move ( value ) .

목차

매개변수

v - 모든 Variants 내 모든 가능한 대안들을 수용하는 Callable
values - 방문자에게 전달할 variant들의 목록

반환값

1) INVOKE 연산의 결과입니다. 반환 타입은 결과에 decltype 을 적용하여 얻은 타입입니다.
2) R 가 (possibly cv-qualified) void 인 경우 아무것도 반환하지 않음; 그렇지 않으면 INVOKE<R> 연산의 결과를 반환함.
3-6) std::variant 값으로 변환된 value .

예외

std::bad_variant_access 를 던집니다, 만약 as-variant ( value_i ) . valueless_by_exception ( ) true 인 경우 values 내의 임의의 variant value_i 에 대해.

복잡도

변형체의 개수가 0 또는 1일 때, 호출 가능 객체의 호출은 상수 시간에 구현됩니다. 즉, 변형체에 저장될 수 있는 타입들의 개수에 의존하지 않습니다.

변형의 수가 하나보다 많을 경우, 호출 가능 객체의 호출에는 복잡도 요구 사항이 없습니다.

참고 사항

n ( 1 * ... * std:: variant_size_v < std:: remove_reference_t < VariantBases >> ) 이라고 할 때, 구현체들은 일반적으로 std::visit 의 모든 특수화에 대해 n 개의 함수 포인터 배열(다차원일 수 있음)과 동등한 테이블을 생성하며, 이는 가상 함수 의 구현과 유사합니다.

구현체들은 또한 switch 문 n 개의 분기로 생성할 수 있습니다 std::visit 의 경우 (예: MSVC STL 구현체는 n 이 256을 초과하지 않을 때 switch 문을 사용합니다).

일반적인 구현에서, v 호출의 시간 복잡도는 (다차원일 수 있는) 배열의 요소 접근 또는 switch 문 실행의 시간 복잡도와 동등하다고 간주할 수 있습니다.

기능 테스트 매크로 표준 기능
__cpp_lib_variant 202102L (C++23)
(DR17)
std::visit for classes derived from std::variant

예제

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
// 방문할 variant
using value_t = std::variant<int, long, double, std::string>;
// visitor #4를 위한 헬퍼 타입
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// 명시적 추론 가이드 (C++20부터는 필요하지 않음)
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
int main()
{
    std::vector<value_t> vec = {10, 15l, 1.5, "hello"};
    for (auto& v: vec)
    {
        // 1. void visitor, 부작용만을 위해 호출됨 (여기서는 I/O용)
        std::visit([](auto&& arg){ std::cout << arg; }, v);
        // 2. value-returning visitor, value-returning visitor 패턴, 다른 variant를 반환하는 관용구를 보여줌
        value_t w = std::visit([](auto&& arg) -> value_t { return arg + arg; }, v);
        // 3. type-matching visitor: 각 타입을 다르게 처리하는 람다
        std::cout << ". 두 배로 증가한 후, variant이 보유하는 값은 ";
        std::visit([](auto&& arg)
        {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "값이 있는 int " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "long 값 " << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "값을 가진 double" << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "값을 가진 std::string " << std::quoted(arg) << '\n';
            else
                static_assert(false, "비완전 방문자!");
        }, w);
    }
    for (auto& v: vec)
    {
        // 4. another type-matching visitor: a class with 3 overloaded operator()'s
        // 참고: `(auto arg)` 템플릿 operator()는 `int`와 `long`에 바인딩됩니다
        //       이 경우에는, 하지만 그것이 없을 때 `(double arg)` operator()
        //       *will also* bind to `int` and `long` because both are implicitly
        //       double로 변환 가능해야 합니다. 이 형식을 사용할 때는 주의를 기울여야
        //       암시적 변환이 올바르게 처리되는지 확인합니다.
        std::visit(overloaded{
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
        }, v);
    }
}

출력:

10. 배가 후, variant는 값 20을 가진 int를 보유함
15. 배가 후, variant는 값 30을 가진 long을 보유함
1.5. 배가 후, variant는 값 3을 가진 double을 보유함
hello. 배가 후, variant는 값 "hellohello"를 가진 std::string을 보유함
10 15 1.500000 "hello"

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
LWG 2970 C++17 오버로드 (1) 의 반환 타입이
INVOKE 연산 결과의 값 범주를
보존하지 않음
보존함
LWG 3052
( P2162R2 )
C++17 Variants 내 어떤 타입이
std::variant 가 아닐 경우
효과가 명시되지 않음
명시함

참고 항목

(C++26)
제공된 함수자를 variant 가 보유한 인자와 함께 호출합니다
(public member function)
다른 variant 와 교환합니다
(public member function)