std:: visit
|
헤더에 정의됨
<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
)
개의 타입 패크)로 주어집니다:
INVOKE
(
std::
forward
<
Visitor
>
(
v
)
,
std
::
get
<
indices
>
(
std::
forward
<
VariantBases
>
(
values
)
)
...
)
,
as-variant
(
values
)
.
index
(
)
...
입니다.
INVOKE<R>
(
std::
forward
<
Visitor
>
(
v
)
,
std
::
get
<
indices
>
(
std::
forward
<
VariantBases
>
(
values
)
)
...
)
,
as-variant
(
values
)
.
index
(
)
...
입니다.
이 오버로드들은
VariantBases
의 모든 타입이 유효한 타입일 때만 오버로드 해결에 참여합니다.
INVOKE
또는
INVOKE<R>
(C++20부터)
로 표시된 표현식이 유효하지 않거나,
INVOKE
또는
INVOKE<R>
(C++20부터)
의 결과가 서로 다른
indices
에 대해 다른 타입이나 값 범주를 가지는 경우, 프로그램은 형식이 잘못되었습니다.
as-variant
함수 템플릿은 해당 타입이
추론될 수 있는
값을 받아들여
std::
variant
<
Ts...
>
(즉,
std::
variant
<
Ts...
>
또는
std::
variant
<
Ts...
>
에서 파생된 타입)에 대한 값을 반환하며, 동일한 const 한정자와 값 범주를 가진
std::variant
값을 반환합니다.
목차 |
매개변수
| v | - | 모든 Variants 내 모든 가능한 대안들을 수용하는 Callable |
| values | - | 방문자에게 전달할 variant들의 목록 |
반환값
예외
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) |