최근 수정 시각 : 2025-12-09 01:15:18

C++/문법/람다 표현식

파일:관련 문서 아이콘.svg   관련 문서: C++
#!if 문서명2 != null
, [[람다식]]
#!if 문서명3 != null
, [[함수형 프로그래밍]]
#!if 문서명4 != null
, [[]]
#!if 문서명5 != null
, [[]]
#!if 문서명6 != null
, [[]]

파일:상위 문서 아이콘.svg   상위 문서: C++/문법
프로그래밍 언어 문법
{{{#!folding [ 펼치기 · 접기 ]
{{{#!wiki style="margin: 0 -10px -5px; word-break: keep-all"
프로그래밍 언어 문법
C(포인터 · 구조체 · size_t) · C++(이름공간 · 클래스 · 특성 · 상수 표현식 · 람다 표현식 · 템플릿/제약조건/메타 프로그래밍) · C# · Forth · Java · Python(함수 · 모듈) · Kotlin · MATLAB · SQL · PHP · JavaScript(표준 내장 객체, this) · Haskell(모나드) ·
마크업 언어 문법
HTML · CSS
개념과 용어
함수(인라인 함수 · 고차 함수 · 콜백 함수 · 람다식) · 리터럴 · 문자열 · 식별자(예약어) · 상속 · 예외 · 조건문 · 반복문 · 비트 연산 · 참조에 의한 호출 · eval · 네임스페이스 · 호이스팅
기타
#! · == · === · deprecated · GOTO · NaN · null · undefined · S-표현식 · 배커스-나우르 표기법 · 콰인(프로그래밍)
}}}}}}
프로그래밍 언어 목록 · 분류 · 문법 · 예제

1. 개요2. 매개변수와 반환 자료형
2.1. 완벽한 매개변수 전달
3. 람다 캡처
3.1. 복사 포섭3.2. 참조 포섭3.3. 기본사항 포섭3.4. 클래스 인스턴스 포섭3.5. 예제1: 스레드를 넘나드는 람다 표현식
4. 포섭의 제한 사항
4.1. 정적 변수 사용4.2. 중복 포섭4.3. 참조 대상 소실
5. 특성 적용6. 상수 람다 표현식7. 템플릿 람다 표현식8. 함수의 매개변수로 전달
8.1. 개념 (Concept) 매개변수로 전달
9. 함수 포인터로 변환10. 정체
10.1. 상태가 없는 클로저10.2. 상태가 없는 일반화 클로저10.3. 상태를 가진 클로저10.4. 상태를 가진 일반화 클로저
11. 둘러보기

1. 개요


#!if attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if head_keyword != null
##======================================= include and import
'''{{{#569cd6 {{{auto}}}}}}'''
#!if import != null
'''{{{#569cd6 {{{import}}}}}}'''{{{#c8865e {{{ <>}}}}}}{{{;}}}
#!if include != null
{{{#include }}}
#!if (template_available = (template_p0 != null || template_v0 != null || template_p1 != null || template_v1 != null || template_p2 != null || template_v2 != null || template_p3 != null || template_v3 != null)) || template_last_label != null
##======================================= template parameter 0
##======================================= template parameter 0 concept
{{{<}}}{{{#!if template_concept0_available = (template_cpt0 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept0_p0 != null || template_concept0_v0 != null || template_concept0_last_label != null
{{{<}}}{{{#!if template_concept0_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p0 != null
{{{#!if !template_concept0_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p0_post != null
{{{}}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v0 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p0_post != null
{{{ }}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_p1 != null || template_v1 != null
##======================================= template parameter 1
{{{, }}}}}}{{{#!if template_concept1_available = (template_cpt1 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept1_p0 != null || template_concept1_v0 != null || template_concept1_last_label != null
{{{<}}}{{{#!if template_concept1_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p1 != null
{{{#!if !template_concept1_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p1_post != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v1 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p1_post != null
{{{}}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_p2 != null || template_v2 != null
##======================================= template parameter 2
{{{, }}}}}}{{{#!if template_concept2_available = (template_cpt2 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept2_p0 != null || template_concept2_v0 != null || template_concept2_last_label != null
{{{<}}}{{{#!if template_concept2_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p2 != null
{{{#!if !template_concept2_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p2_post != null
{{{}}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v2 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p2_post != null
{{{ }}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_last_label == null
{{{>}}}}}}{{{#!if template_last_label != null
##======================================= template parameters end
{{{>}}}}}}
#!if pre_available = (kw1 != null || kw1_post != null || kw2 != null || kw2_post != null || cls_attribute != null || cls_attribute_lnk != null || ns_end != null || pre1_t != null || pre2_t != null || pre_e != null)
#!if ns_available = (ns != null || ns1 != null || ns2 != null || ns3 != null)
#!if body_available = (body_number != null || body_string != null || body_v != null || body_gv != null || body_f != null || body_mv != null || body_mf != null || body_static_mv != null || body_static_mf != null || body_post != null)
#!if head_keyword != null && (pre_available || body_available || ns != null || ns1 != null)
{{{ }}}
#!if fn_attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if fn_attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if kw1 != null
'''{{{#569cd6 {{{contexpr}}}}}}'''{{{#!if kw1_post != null
{{{}}}}}}{{{#!if kw1_post == null && kw2 != null
{{{ }}}}}}
#!if kw2 != null
'''{{{#CornFlowerBlue {{{long long}}}}}}'''{{{#!if kw2_post != null
{{{&&}}}}}}{{{#!if kw2_post == null && (cls_attribute != null || cls_attribute_lnk != null)
{{{ }}}}}}
#!if cls_attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]
#!if cls_attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]
#!if (head_keyword != null || pre_available) && (body_available || ns_available)
##======================================= Namespaces
{{{ }}}
#!if ns != null
'''{{{#58fafe {{{}}}}}}'''
#!if ns1 != null
{{{#!if ns1_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{std}}}}}}'''
#!if ns1_post != null
{{{  }}}
#!if ns2 != null
{{{#!if ns1_post == null
{{{::}}}}}}{{{#!if ns2_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{chrono}}}}}}'''
#!if ns2_post != null
{{{  }}}
#!if ns3 != null
{{{#!if ns2_post == null
{{{::}}}}}}{{{#!if ns3_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{chrono_literals}}}}}}'''
#!if ns3_post != null
{{{  }}}
#!if ns1 != null && ns_end == null && (body_available || pre_available)
{{{#!if ns3_post == null
{{{::}}}}}}
#!if ns1 != null && ns_end != null
##======================================= Front-end types
{{{}}}
#!if pre1_t != null
{{{#4ec9b0,#6fdbba {{{system_clock}}}}}}
#!if pre2_t != null
{{{::}}}{{{#4ec9b0,#6fdbba {{{duration}}}}}}
#!if pre_e != null
{{{::}}}{{{#f0f068 {{{enum}}}}}}
#!if pre_post != null
##======================================= body begin
{{{}}}
#!if body_available && pre_available && !ns_available
{{{ }}}
#!if body_number != null
{{{#b5cea8 {{{}}}}}}
#!if body_string != null
{{{#c8865e {{{}}}}}}
#!if body_v != null
{{{#a9a9b0,#a1a1a2 {{{표현식-식별자}}}}}}
#!if body_gv != null
{{{#ffa3d2 {{{}}}}}}
#!if body_mv != null
{{{#ffffff {{{}}}}}}
#!if body_f != null
{{{#f87a7a {{{}}}}}}
#!if body_mf != null
{{{#f0a962 {{{}}}}}}
#!if body_static_mv != null
{{{#ffffff '''{{{}}}'''}}}
#!if body_static_mf != null
{{{#f0a962 '''{{{}}}'''}}}
#!if body_post != null
{{{}}}
#!if body_tmpopen != null
{{{<}}}
#!if body_bopen != null
##======================================= body end
##======================================= arguments begin
{{{(}}}
#!if arg1_pre_available = (arg1_concept != null || arg1_kw != null || arg1_t_kw != null || arg1_t != null)
#!if arg2_pre_available = (arg2_concept != null || arg2_kw != null || arg2_t_kw != null || arg2_t != null)
#!if arg3_pre_available = (arg3_concept != null || arg3_kw != null || arg3_t_kw != null || arg3_t != null)
#!if arg4_pre_available = (arg4_concept != null || arg4_kw != null || arg4_t_kw != null || arg4_t != null)
#!if arg1_concept != null
##======================================= argument 1
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg1_concept_tparam1 != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg1_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg1_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg1_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg1_t_kw!=null
{{{#!if arg1_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg1_t!=null
{{{#!if arg1_kw != null || arg1_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg1_t_post!=null
{{{}}}
#!if arg1_param != null
{{{#!if !arg1_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg1_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg1_pre_available || arg1_param != null) && (arg2_pre_available || arg2_param != null)
{{{, }}}
#!if arg2_concept!=null
##======================================= argument 2
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg2_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if ar2_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg2_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg2_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg2_t_kw!=null
{{{#!if arg2_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg2_t!=null
{{{#!if arg2_kw != null || arg2_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg2_t_post!=null
{{{}}}
#!if arg2_param != null
{{{#!if !arg2_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg2_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg2_pre_available || arg2_param != null) && (arg3_pre_available || arg3_param != null)
{{{, }}}
#!if arg3_concept!=null
##======================================= argument 3
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg3_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg3_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg3_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg3_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg3_t_kw!=null
{{{#!if arg3_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg3_t!=null
{{{#!if arg3_kw != null || arg3_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg3_t_post!=null
{{{}}}
#!if arg3_param != null
{{{#!if !arg3_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg3_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg3_pre_available || arg3_param != null) && (arg4_pre_available || arg4_param != null)
{{{, }}}
#!if arg4_concept!=null
##======================================= argument4
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg4_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg4_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg4_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg4_kw != null
{{{#!if arg4_kw != null
{{{ }}}}}}'''{{{#569cd6 {{{const}}}}}}'''
#!if arg4_t_kw!=null
'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg4_t!=null
{{{#!if arg4_kw != null || arg4_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg4_t_post!=null
{{{}}}
#!if arg4_param != null
{{{#!if !arg4_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg4_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if arg5_param != null
##======================================= argument5, argument6
{{{#bcdce6 {{{, }}}}}}
#!if arg6_param != null
{{{#bcdce6 {{{, }}}}}}
#!if arg_last_dots != null
{{{, ...}}}
#!if body_bopen != null
##======================================= arguments end
##======================================= body end
##======================================= specifiers begin
{{{#!if body_spec1 != null
{{{) }}}}}}{{{#!if body_spec1 == null
{{{)}}}}}}
#!if body_spec1 != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if body_spec_assign != null
{{{ = }}}'''{{{#569cd6 {{{default}}}}}}'''
#!if body_spec1_paren != null
{{{(}}}
#!if body_spec1_ref != null
{{{}}}
#!if body_spec2 != null
{{{#!if body_spec1 != null && body_spec1_paren == null
{{{ }}}}}}'''{{{#569cd6 {{{noexcept}}}}}}'''
#!if body_spec2_paren != null
{{{(}}}
#!if body_spec2_label != null
{{{}}}
#!if body_spec2_paren != null
{{{)}}}
#!if body_spec1_paren != null
##======================================= specifiers end
##======================================= trailing begin
{{{)}}}
#!if trailing != null
{{{  }}}
#!if trailing_keyword != null
'''{{{#569cd6 {{{decltype}}}}}}'''
#!if trailing_bopen != null
{{{(}}}
#!if trailing_content_t1 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if trailing_content_f != null
{{{#f87a7a {{{}}}}}}
#!if trailing_label != null
{{{}}}
#!if trailing_bopen != null
{{{)}}}
#!if label_last != null
##======================================= trailing end
{{{}}}
#!if body_tmpopen != null
##======================================= footer
{{{>}}}
#!if last != null
{{{}}}



[include(틀:C++ 요소, fn_attribute=함수-특성, body_post=[람다-포섭...], arg1_t=매개변수1-자료형, arg1_param=매개변수1, arg2_t=매개변수2-자료형, arg2_param=매개변수2, body_bopen=1, arg_last_dots=1, body_spec1=noexcept, body_spec1_paren=1, body_spec2_label=예외-사양...)]
#!if attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if head_keyword != null
##======================================= include and import
'''{{{#569cd6 {{{{}}}}}}'''
#!if import != null
'''{{{#569cd6 {{{import}}}}}}'''{{{#c8865e {{{ <>}}}}}}{{{;}}}
#!if include != null
{{{#include }}}
#!if (template_available = (template_p0 != null || template_v0 != null || template_p1 != null || template_v1 != null || template_p2 != null || template_v2 != null || template_p3 != null || template_v3 != null)) || template_last_label != null
##======================================= template parameter 0
##======================================= template parameter 0 concept
{{{<}}}{{{#!if template_concept0_available = (template_cpt0 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept0_p0 != null || template_concept0_v0 != null || template_concept0_last_label != null
{{{<}}}{{{#!if template_concept0_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p0 != null
{{{#!if !template_concept0_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p0_post != null
{{{}}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v0 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p0_post != null
{{{ }}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_p1 != null || template_v1 != null
##======================================= template parameter 1
{{{, }}}}}}{{{#!if template_concept1_available = (template_cpt1 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept1_p0 != null || template_concept1_v0 != null || template_concept1_last_label != null
{{{<}}}{{{#!if template_concept1_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p1 != null
{{{#!if !template_concept1_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p1_post != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v1 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p1_post != null
{{{}}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_p2 != null || template_v2 != null
##======================================= template parameter 2
{{{, }}}}}}{{{#!if template_concept2_available = (template_cpt2 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept2_p0 != null || template_concept2_v0 != null || template_concept2_last_label != null
{{{<}}}{{{#!if template_concept2_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p2 != null
{{{#!if !template_concept2_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p2_post != null
{{{}}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v2 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p2_post != null
{{{ }}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_last_label == null
{{{>}}}}}}{{{#!if template_last_label != null
##======================================= template parameters end
{{{>}}}}}}
#!if pre_available = (kw1 != null || kw1_post != null || kw2 != null || kw2_post != null || cls_attribute != null || cls_attribute_lnk != null || ns_end != null || pre1_t != null || pre2_t != null || pre_e != null)
#!if ns_available = (ns != null || ns1 != null || ns2 != null || ns3 != null)
#!if body_available = (body_number != null || body_string != null || body_v != null || body_gv != null || body_f != null || body_mv != null || body_mf != null || body_static_mv != null || body_static_mf != null || body_post != null)
#!if head_keyword != null && (pre_available || body_available || ns != null || ns1 != null)
{{{ }}}
#!if fn_attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if fn_attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if kw1 != null
'''{{{#569cd6 {{{contexpr}}}}}}'''{{{#!if kw1_post != null
{{{}}}}}}{{{#!if kw1_post == null && kw2 != null
{{{ }}}}}}
#!if kw2 != null
'''{{{#CornFlowerBlue {{{long long}}}}}}'''{{{#!if kw2_post != null
{{{&&}}}}}}{{{#!if kw2_post == null && (cls_attribute != null || cls_attribute_lnk != null)
{{{ }}}}}}
#!if cls_attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]
#!if cls_attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]
#!if (head_keyword != null || pre_available) && (body_available || ns_available)
##======================================= Namespaces
{{{ }}}
#!if ns != null
'''{{{#58fafe {{{}}}}}}'''
#!if ns1 != null
{{{#!if ns1_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{std}}}}}}'''
#!if ns1_post != null
{{{  }}}
#!if ns2 != null
{{{#!if ns1_post == null
{{{::}}}}}}{{{#!if ns2_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{chrono}}}}}}'''
#!if ns2_post != null
{{{  }}}
#!if ns3 != null
{{{#!if ns2_post == null
{{{::}}}}}}{{{#!if ns3_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{chrono_literals}}}}}}'''
#!if ns3_post != null
{{{  }}}
#!if ns1 != null && ns_end == null && (body_available || pre_available)
{{{#!if ns3_post == null
{{{::}}}}}}
#!if ns1 != null && ns_end != null
##======================================= Front-end types
{{{}}}
#!if pre1_t != null
{{{#4ec9b0,#6fdbba {{{system_clock}}}}}}
#!if pre2_t != null
{{{::}}}{{{#4ec9b0,#6fdbba {{{duration}}}}}}
#!if pre_e != null
{{{::}}}{{{#f0f068 {{{enum}}}}}}
#!if pre_post != null
##======================================= body begin
{{{}}}
#!if body_available && pre_available && !ns_available
{{{ }}}
#!if body_number != null
{{{#b5cea8 {{{}}}}}}
#!if body_string != null
{{{#c8865e {{{}}}}}}
#!if body_v != null
{{{#a9a9b0,#a1a1a2 {{{}}}}}}
#!if body_gv != null
{{{#ffa3d2 {{{}}}}}}
#!if body_mv != null
{{{#ffffff {{{}}}}}}
#!if body_f != null
{{{#f87a7a {{{}}}}}}
#!if body_mf != null
{{{#f0a962 {{{}}}}}}
#!if body_static_mv != null
{{{#ffffff '''{{{}}}'''}}}
#!if body_static_mf != null
{{{#f0a962 '''{{{}}}'''}}}
#!if body_post != null
{{{}}}
#!if body_tmpopen != null
{{{<}}}
#!if body_bopen != null
##======================================= body end
##======================================= arguments begin
{{{(}}}
#!if arg1_pre_available = (arg1_concept != null || arg1_kw != null || arg1_t_kw != null || arg1_t != null)
#!if arg2_pre_available = (arg2_concept != null || arg2_kw != null || arg2_t_kw != null || arg2_t != null)
#!if arg3_pre_available = (arg3_concept != null || arg3_kw != null || arg3_t_kw != null || arg3_t != null)
#!if arg4_pre_available = (arg4_concept != null || arg4_kw != null || arg4_t_kw != null || arg4_t != null)
#!if arg1_concept != null
##======================================= argument 1
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg1_concept_tparam1 != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg1_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg1_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg1_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg1_t_kw!=null
{{{#!if arg1_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg1_t!=null
{{{#!if arg1_kw != null || arg1_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg1_t_post!=null
{{{}}}
#!if arg1_param != null
{{{#!if !arg1_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg1_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg1_pre_available || arg1_param != null) && (arg2_pre_available || arg2_param != null)
{{{, }}}
#!if arg2_concept!=null
##======================================= argument 2
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg2_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if ar2_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg2_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg2_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg2_t_kw!=null
{{{#!if arg2_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg2_t!=null
{{{#!if arg2_kw != null || arg2_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg2_t_post!=null
{{{}}}
#!if arg2_param != null
{{{#!if !arg2_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg2_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg2_pre_available || arg2_param != null) && (arg3_pre_available || arg3_param != null)
{{{, }}}
#!if arg3_concept!=null
##======================================= argument 3
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg3_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg3_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg3_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg3_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg3_t_kw!=null
{{{#!if arg3_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg3_t!=null
{{{#!if arg3_kw != null || arg3_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg3_t_post!=null
{{{}}}
#!if arg3_param != null
{{{#!if !arg3_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg3_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg3_pre_available || arg3_param != null) && (arg4_pre_available || arg4_param != null)
{{{, }}}
#!if arg4_concept!=null
##======================================= argument4
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg4_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg4_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg4_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg4_kw != null
{{{#!if arg4_kw != null
{{{ }}}}}}'''{{{#569cd6 {{{const}}}}}}'''
#!if arg4_t_kw!=null
'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg4_t!=null
{{{#!if arg4_kw != null || arg4_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg4_t_post!=null
{{{}}}
#!if arg4_param != null
{{{#!if !arg4_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg4_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if arg5_param != null
##======================================= argument5, argument6
{{{#bcdce6 {{{, }}}}}}
#!if arg6_param != null
{{{#bcdce6 {{{, }}}}}}
#!if arg_last_dots != null
{{{, ...}}}
#!if body_bopen != null
##======================================= arguments end
##======================================= body end
##======================================= specifiers begin
{{{#!if body_spec1 != null
{{{) }}}}}}{{{#!if body_spec1 == null
{{{)}}}}}}
#!if body_spec1 != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if body_spec_assign != null
{{{ = }}}'''{{{#569cd6 {{{default}}}}}}'''
#!if body_spec1_paren != null
{{{(}}}
#!if body_spec1_ref != null
{{{}}}
#!if body_spec2 != null
{{{#!if body_spec1 != null && body_spec1_paren == null
{{{ }}}}}}'''{{{#569cd6 {{{noexcept}}}}}}'''
#!if body_spec2_paren != null
{{{(}}}
#!if body_spec2_label != null
{{{}}}
#!if body_spec2_paren != null
{{{)}}}
#!if body_spec1_paren != null
##======================================= specifiers end
##======================================= trailing begin
{{{)}}}
#!if trailing != null
{{{  }}}
#!if trailing_keyword != null
'''{{{#569cd6 {{{decltype}}}}}}'''
#!if trailing_bopen != null
{{{(}}}
#!if trailing_content_t1 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if trailing_content_f != null
{{{#f87a7a {{{}}}}}}
#!if trailing_label != null
{{{}}}
#!if trailing_bopen != null
{{{)}}}
#!if label_last != null
##======================================= trailing end
{{{}}}
#!if body_tmpopen != null
##======================================= footer
{{{>}}}
#!if last != null
{{{}}}


#!if attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if head_keyword != null
##======================================= include and import
'''{{{#569cd6 {{{}}}}}}'''
#!if import != null
'''{{{#569cd6 {{{import}}}}}}'''{{{#c8865e {{{ <>}}}}}}{{{;}}}
#!if include != null
{{{#include }}}
#!if (template_available = (template_p0 != null || template_v0 != null || template_p1 != null || template_v1 != null || template_p2 != null || template_v2 != null || template_p3 != null || template_v3 != null)) || template_last_label != null
##======================================= template parameter 0
##======================================= template parameter 0 concept
{{{<}}}{{{#!if template_concept0_available = (template_cpt0 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept0_p0 != null || template_concept0_v0 != null || template_concept0_last_label != null
{{{<}}}{{{#!if template_concept0_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p0 != null
{{{#!if !template_concept0_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p0_post != null
{{{}}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v0 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p0_post != null
{{{ }}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_p1 != null || template_v1 != null
##======================================= template parameter 1
{{{, }}}}}}{{{#!if template_concept1_available = (template_cpt1 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept1_p0 != null || template_concept1_v0 != null || template_concept1_last_label != null
{{{<}}}{{{#!if template_concept1_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p1 != null
{{{#!if !template_concept1_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p1_post != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v1 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p1_post != null
{{{}}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_p2 != null || template_v2 != null
##======================================= template parameter 2
{{{, }}}}}}{{{#!if template_concept2_available = (template_cpt2 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept2_p0 != null || template_concept2_v0 != null || template_concept2_last_label != null
{{{<}}}{{{#!if template_concept2_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p2 != null
{{{#!if !template_concept2_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p2_post != null
{{{}}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v2 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p2_post != null
{{{ }}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_last_label == null
{{{>}}}}}}{{{#!if template_last_label != null
##======================================= template parameters end
{{{>}}}}}}
#!if pre_available = (kw1 != null || kw1_post != null || kw2 != null || kw2_post != null || cls_attribute != null || cls_attribute_lnk != null || ns_end != null || pre1_t != null || pre2_t != null || pre_e != null)
#!if ns_available = (ns != null || ns1 != null || ns2 != null || ns3 != null)
#!if body_available = (body_number != null || body_string != null || body_v != null || body_gv != null || body_f != null || body_mv != null || body_mf != null || body_static_mv != null || body_static_mf != null || body_post != null)
#!if head_keyword != null && (pre_available || body_available || ns != null || ns1 != null)
{{{ }}}
#!if fn_attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if fn_attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if kw1 != null
'''{{{#569cd6 {{{contexpr}}}}}}'''{{{#!if kw1_post != null
{{{}}}}}}{{{#!if kw1_post == null && kw2 != null
{{{ }}}}}}
#!if kw2 != null
'''{{{#CornFlowerBlue {{{long long}}}}}}'''{{{#!if kw2_post != null
{{{&&}}}}}}{{{#!if kw2_post == null && (cls_attribute != null || cls_attribute_lnk != null)
{{{ }}}}}}
#!if cls_attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]
#!if cls_attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]
#!if (head_keyword != null || pre_available) && (body_available || ns_available)
##======================================= Namespaces
{{{ }}}
#!if ns != null
'''{{{#58fafe {{{}}}}}}'''
#!if ns1 != null
{{{#!if ns1_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{std}}}}}}'''
#!if ns1_post != null
{{{  }}}
#!if ns2 != null
{{{#!if ns1_post == null
{{{::}}}}}}{{{#!if ns2_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{chrono}}}}}}'''
#!if ns2_post != null
{{{  }}}
#!if ns3 != null
{{{#!if ns2_post == null
{{{::}}}}}}{{{#!if ns3_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{chrono_literals}}}}}}'''
#!if ns3_post != null
{{{  }}}
#!if ns1 != null && ns_end == null && (body_available || pre_available)
{{{#!if ns3_post == null
{{{::}}}}}}
#!if ns1 != null && ns_end != null
##======================================= Front-end types
{{{}}}
#!if pre1_t != null
{{{#4ec9b0,#6fdbba {{{system_clock}}}}}}
#!if pre2_t != null
{{{::}}}{{{#4ec9b0,#6fdbba {{{duration}}}}}}
#!if pre_e != null
{{{::}}}{{{#f0f068 {{{enum}}}}}}
#!if pre_post != null
##======================================= body begin
{{{}}}
#!if body_available && pre_available && !ns_available
{{{ }}}
#!if body_number != null
{{{#b5cea8 {{{}}}}}}
#!if body_string != null
{{{#c8865e {{{}}}}}}
#!if body_v != null
{{{#a9a9b0,#a1a1a2 {{{}}}}}}
#!if body_gv != null
{{{#ffa3d2 {{{}}}}}}
#!if body_mv != null
{{{#ffffff {{{}}}}}}
#!if body_f != null
{{{#f87a7a {{{}}}}}}
#!if body_mf != null
{{{#f0a962 {{{}}}}}}
#!if body_static_mv != null
{{{#ffffff '''{{{}}}'''}}}
#!if body_static_mf != null
{{{#f0a962 '''{{{}}}'''}}}
#!if body_post != null
{{{}}}
#!if body_tmpopen != null
{{{<}}}
#!if body_bopen != null
##======================================= body end
##======================================= arguments begin
{{{(}}}
#!if arg1_pre_available = (arg1_concept != null || arg1_kw != null || arg1_t_kw != null || arg1_t != null)
#!if arg2_pre_available = (arg2_concept != null || arg2_kw != null || arg2_t_kw != null || arg2_t != null)
#!if arg3_pre_available = (arg3_concept != null || arg3_kw != null || arg3_t_kw != null || arg3_t != null)
#!if arg4_pre_available = (arg4_concept != null || arg4_kw != null || arg4_t_kw != null || arg4_t != null)
#!if arg1_concept != null
##======================================= argument 1
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg1_concept_tparam1 != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg1_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg1_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg1_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg1_t_kw!=null
{{{#!if arg1_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg1_t!=null
{{{#!if arg1_kw != null || arg1_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg1_t_post!=null
{{{}}}
#!if arg1_param != null
{{{#!if !arg1_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg1_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg1_pre_available || arg1_param != null) && (arg2_pre_available || arg2_param != null)
{{{, }}}
#!if arg2_concept!=null
##======================================= argument 2
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg2_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if ar2_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg2_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg2_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg2_t_kw!=null
{{{#!if arg2_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg2_t!=null
{{{#!if arg2_kw != null || arg2_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg2_t_post!=null
{{{}}}
#!if arg2_param != null
{{{#!if !arg2_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg2_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg2_pre_available || arg2_param != null) && (arg3_pre_available || arg3_param != null)
{{{, }}}
#!if arg3_concept!=null
##======================================= argument 3
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg3_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg3_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg3_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg3_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg3_t_kw!=null
{{{#!if arg3_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg3_t!=null
{{{#!if arg3_kw != null || arg3_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg3_t_post!=null
{{{}}}
#!if arg3_param != null
{{{#!if !arg3_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg3_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg3_pre_available || arg3_param != null) && (arg4_pre_available || arg4_param != null)
{{{, }}}
#!if arg4_concept!=null
##======================================= argument4
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg4_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg4_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg4_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg4_kw != null
{{{#!if arg4_kw != null
{{{ }}}}}}'''{{{#569cd6 {{{const}}}}}}'''
#!if arg4_t_kw!=null
'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg4_t!=null
{{{#!if arg4_kw != null || arg4_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg4_t_post!=null
{{{}}}
#!if arg4_param != null
{{{#!if !arg4_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg4_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if arg5_param != null
##======================================= argument5, argument6
{{{#bcdce6 {{{, }}}}}}
#!if arg6_param != null
{{{#bcdce6 {{{, }}}}}}
#!if arg_last_dots != null
{{{, ...}}}
#!if body_bopen != null
##======================================= arguments end
##======================================= body end
##======================================= specifiers begin
{{{#!if body_spec1 != null
{{{) }}}}}}{{{#!if body_spec1 == null
{{{)}}}}}}
#!if body_spec1 != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if body_spec_assign != null
{{{ = }}}'''{{{#569cd6 {{{default}}}}}}'''
#!if body_spec1_paren != null
{{{(}}}
#!if body_spec1_ref != null
{{{}}}
#!if body_spec2 != null
{{{#!if body_spec1 != null && body_spec1_paren == null
{{{ }}}}}}'''{{{#569cd6 {{{noexcept}}}}}}'''
#!if body_spec2_paren != null
{{{(}}}
#!if body_spec2_label != null
{{{}}}
#!if body_spec2_paren != null
{{{)}}}
#!if body_spec1_paren != null
##======================================= specifiers end
##======================================= trailing begin
{{{)}}}
#!if trailing != null
{{{  }}}
#!if trailing_keyword != null
'''{{{#569cd6 {{{decltype}}}}}}'''
#!if trailing_bopen != null
{{{(}}}
#!if trailing_content_t1 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if trailing_content_f != null
{{{#f87a7a {{{}}}}}}
#!if trailing_label != null
{{{}}}
#!if trailing_bopen != null
{{{)}}}
#!if label_last != null
##======================================= trailing end
{{{}}}
#!if body_tmpopen != null
##======================================= footer
{{{>}}}
#!if last != null
{{{...;}}}


#!if attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if head_keyword != null
##======================================= include and import
'''{{{#569cd6 {{{}}}}}}}'''
#!if import != null
'''{{{#569cd6 {{{import}}}}}}'''{{{#c8865e {{{ <>}}}}}}{{{;}}}
#!if include != null
{{{#include }}}
#!if (template_available = (template_p0 != null || template_v0 != null || template_p1 != null || template_v1 != null || template_p2 != null || template_v2 != null || template_p3 != null || template_v3 != null)) || template_last_label != null
##======================================= template parameter 0
##======================================= template parameter 0 concept
{{{<}}}{{{#!if template_concept0_available = (template_cpt0 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept0_p0 != null || template_concept0_v0 != null || template_concept0_last_label != null
{{{<}}}{{{#!if template_concept0_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept0_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept0_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p0 != null
{{{#!if !template_concept0_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p0_post != null
{{{}}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v0 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p0_post != null
{{{ }}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_p1 != null || template_v1 != null
##======================================= template parameter 1
{{{, }}}}}}{{{#!if template_concept1_available = (template_cpt1 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept1_p0 != null || template_concept1_v0 != null || template_concept1_last_label != null
{{{<}}}{{{#!if template_concept1_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept1_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept1_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p1 != null
{{{#!if !template_concept1_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p1_post != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v1 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p1_post != null
{{{}}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_p2 != null || template_v2 != null
##======================================= template parameter 2
{{{, }}}}}}{{{#!if template_concept2_available = (template_cpt2 != null)
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if template_concept2_p0 != null || template_concept2_v0 != null || template_concept2_last_label != null
{{{<}}}{{{#!if template_concept2_p0 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v0 != null
{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_p1 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v1 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_p2 != null
{{{, }}}{{{#4ec9b0,#6fdbba {{{}}}}}}}}}{{{#!if template_concept2_v2 != null
{{{, }}}{{{#ffffff {{{}}}}}}}}}{{{#!if template_concept2_last_label != null
{{{}}}}}}{{{>}}}}}}}}}{{{#!if template_p2 != null
{{{#!if !template_concept2_available
'''{{{#569cd6 {{{typename}}}}}}'''}}}{{{#!if template_p2_post != null
{{{}}}}}}{{{#4ec9b0,#6fdbba {{{ }}}}}}}}}{{{#!if template_v2 != null
{{{#4ec9b0,#6fdbba {{{ }}}}}}{{{#!if template_p2_post != null
{{{ }}}}}}{{{#ffffff '''{{{}}}'''}}}}}}{{{#!if template_last_label == null
{{{>}}}}}}{{{#!if template_last_label != null
##======================================= template parameters end
{{{>}}}}}}
#!if pre_available = (kw1 != null || kw1_post != null || kw2 != null || kw2_post != null || cls_attribute != null || cls_attribute_lnk != null || ns_end != null || pre1_t != null || pre2_t != null || pre_e != null)
#!if ns_available = (ns != null || ns1 != null || ns2 != null || ns3 != null)
#!if body_available = (body_number != null || body_string != null || body_v != null || body_gv != null || body_f != null || body_mv != null || body_mf != null || body_static_mv != null || body_static_mf != null || body_post != null)
#!if head_keyword != null && (pre_available || body_available || ns != null || ns1 != null)
{{{ }}}
#!if fn_attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if fn_attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]{{{ }}}
#!if kw1 != null
'''{{{#569cd6 {{{contexpr}}}}}}'''{{{#!if kw1_post != null
{{{}}}}}}{{{#!if kw1_post == null && kw2 != null
{{{ }}}}}}
#!if kw2 != null
'''{{{#CornFlowerBlue {{{long long}}}}}}'''{{{#!if kw2_post != null
{{{&&}}}}}}{{{#!if kw2_post == null && (cls_attribute != null || cls_attribute_lnk != null)
{{{ }}}}}}
#!if cls_attribute != null
[[C++/문법/특성|{{{#a8a8a8 {{{[[]]}}}}}}]]
#!if cls_attribute_lnk != null
[[C++/문법/특성#|{{{#a8a8a8 {{{[[]]}}}}}}]]
#!if (head_keyword != null || pre_available) && (body_available || ns_available)
##======================================= Namespaces
{{{ }}}
#!if ns != null
'''{{{#58fafe {{{}}}}}}'''
#!if ns1 != null
{{{#!if ns1_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{std}}}}}}'''
#!if ns1_post != null
{{{  }}}
#!if ns2 != null
{{{#!if ns1_post == null
{{{::}}}}}}{{{#!if ns2_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{chrono}}}}}}'''
#!if ns2_post != null
{{{  }}}
#!if ns3 != null
{{{#!if ns2_post == null
{{{::}}}}}}{{{#!if ns3_pre_kw != null
'''{{{#569cd6 {{{inline }}}}}}'''}}}'''{{{#58fafe {{{chrono_literals}}}}}}'''
#!if ns3_post != null
{{{  }}}
#!if ns1 != null && ns_end == null && (body_available || pre_available)
{{{#!if ns3_post == null
{{{::}}}}}}
#!if ns1 != null && ns_end != null
##======================================= Front-end types
{{{}}}
#!if pre1_t != null
{{{#4ec9b0,#6fdbba {{{system_clock}}}}}}
#!if pre2_t != null
{{{::}}}{{{#4ec9b0,#6fdbba {{{duration}}}}}}
#!if pre_e != null
{{{::}}}{{{#f0f068 {{{enum}}}}}}
#!if pre_post != null
##======================================= body begin
{{{}}}
#!if body_available && pre_available && !ns_available
{{{ }}}
#!if body_number != null
{{{#b5cea8 {{{}}}}}}
#!if body_string != null
{{{#c8865e {{{}}}}}}
#!if body_v != null
{{{#a9a9b0,#a1a1a2 {{{}}}}}}
#!if body_gv != null
{{{#ffa3d2 {{{}}}}}}
#!if body_mv != null
{{{#ffffff {{{}}}}}}
#!if body_f != null
{{{#f87a7a {{{}}}}}}
#!if body_mf != null
{{{#f0a962 {{{}}}}}}
#!if body_static_mv != null
{{{#ffffff '''{{{}}}'''}}}
#!if body_static_mf != null
{{{#f0a962 '''{{{}}}'''}}}
#!if body_post != null
{{{}}}
#!if body_tmpopen != null
{{{<}}}
#!if body_bopen != null
##======================================= body end
##======================================= arguments begin
{{{(}}}
#!if arg1_pre_available = (arg1_concept != null || arg1_kw != null || arg1_t_kw != null || arg1_t != null)
#!if arg2_pre_available = (arg2_concept != null || arg2_kw != null || arg2_t_kw != null || arg2_t != null)
#!if arg3_pre_available = (arg3_concept != null || arg3_kw != null || arg3_t_kw != null || arg3_t != null)
#!if arg4_pre_available = (arg4_concept != null || arg4_kw != null || arg4_t_kw != null || arg4_t != null)
#!if arg1_concept != null
##======================================= argument 1
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg1_concept_tparam1 != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg1_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg1_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg1_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg1_t_kw!=null
{{{#!if arg1_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg1_t!=null
{{{#!if arg1_kw != null || arg1_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg1_t_post!=null
{{{}}}
#!if arg1_param != null
{{{#!if !arg1_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg1_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg1_pre_available || arg1_param != null) && (arg2_pre_available || arg2_param != null)
{{{, }}}
#!if arg2_concept!=null
##======================================= argument 2
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg2_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if ar2_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg2_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg2_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg2_t_kw!=null
{{{#!if arg2_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg2_t!=null
{{{#!if arg2_kw != null || arg2_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg2_t_post!=null
{{{}}}
#!if arg2_param != null
{{{#!if !arg2_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg2_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg2_pre_available || arg2_param != null) && (arg3_pre_available || arg3_param != null)
{{{, }}}
#!if arg3_concept!=null
##======================================= argument 3
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg3_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg3_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg3_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg3_kw != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if arg3_t_kw!=null
{{{#!if arg3_kw != null
{{{ }}}}}}'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg3_t!=null
{{{#!if arg3_kw != null || arg3_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg3_t_post!=null
{{{}}}
#!if arg3_param != null
{{{#!if !arg3_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg3_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if (arg3_pre_available || arg3_param != null) && (arg4_pre_available || arg4_param != null)
{{{, }}}
#!if arg4_concept!=null
##======================================= argument4
'''{{{#4ec9b0,#6fdbba {{{}}}}}}'''{{{#!if arg4_concept_params != null
{{{<}}}{{{#4ec9b0,#6fdbba {{{}}}}}}{{{#!if arg4_concept_tparam2 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{#!if arg4_concept_tparam3 != null
{{{#4ec9b0,#6fdbba {{{, }}}}}}}}}{{{>}}}}}}{{{ }}}
#!if arg4_kw != null
{{{#!if arg4_kw != null
{{{ }}}}}}'''{{{#569cd6 {{{const}}}}}}'''
#!if arg4_t_kw!=null
'''{{{#CornFlowerBlue {{{int}}}}}}'''
#!if arg4_t!=null
{{{#!if arg4_kw != null || arg4_t_kw != null
{{{ }}}}}}{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if arg4_t_post!=null
{{{}}}
#!if arg4_param != null
{{{#!if !arg4_pre_available
{{{#bcdce6 {{{}}}}}}}}}{{{#!if arg4_pre_available
{{{#bcdce6 {{{ }}}}}}}}}
#!if arg5_param != null
##======================================= argument5, argument6
{{{#bcdce6 {{{, }}}}}}
#!if arg6_param != null
{{{#bcdce6 {{{, }}}}}}
#!if arg_last_dots != null
{{{, ...}}}
#!if body_bopen != null
##======================================= arguments end
##======================================= body end
##======================================= specifiers begin
{{{#!if body_spec1 != null
{{{) }}}}}}{{{#!if body_spec1 == null
{{{)}}}}}}
#!if body_spec1 != null
'''{{{#569cd6 {{{const}}}}}}'''
#!if body_spec_assign != null
{{{ = }}}'''{{{#569cd6 {{{default}}}}}}'''
#!if body_spec1_paren != null
{{{(}}}
#!if body_spec1_ref != null
{{{}}}
#!if body_spec2 != null
{{{#!if body_spec1 != null && body_spec1_paren == null
{{{ }}}}}}'''{{{#569cd6 {{{noexcept}}}}}}'''
#!if body_spec2_paren != null
{{{(}}}
#!if body_spec2_label != null
{{{}}}
#!if body_spec2_paren != null
{{{)}}}
#!if body_spec1_paren != null
##======================================= specifiers end
##======================================= trailing begin
{{{)}}}
#!if trailing != null
{{{  }}}
#!if trailing_keyword != null
'''{{{#569cd6 {{{decltype}}}}}}'''
#!if trailing_bopen != null
{{{(}}}
#!if trailing_content_t1 != null
{{{#4ec9b0,#6fdbba {{{}}}}}}
#!if trailing_content_f != null
{{{#f87a7a {{{}}}}}}
#!if trailing_label != null
{{{}}}
#!if trailing_bopen != null
{{{)}}}
#!if label_last != null
##======================================= trailing end
{{{}}}
#!if body_tmpopen != null
##======================================= footer
{{{>}}}
#!if last != null
{{{}}}


람다 표현식 (Lambda Expression)
람다 표현식, 혹은 익명 함수는 C++11에서 추가된 새로운 기능으로써 언제 어디에서나 실행시킬 수 있는 함수를 만들고, 매개변수로 전달하고, 제어할 수 있는 기능이다. auto와 함께 일반 사용자들이 가장 자주 쓰게될 모던 C++의 기능이다.

람다 표현식은 함수와 똑같은 방식으로 사용할 수 있다. 또한 복사와 이동이 자유롭다. 이 문서에서는 람다 표현식의 작성 방법, 간단한 예제와 활용하는 방법을 알아보도록 한다.

2. 매개변수와 반환 자료형

#!syntax cpp
int main()
{
    // (1) 정수를 반환하는 람다 표현식
    auto lambda0 = [] { return 1; };

    // `lambda0_result`는 1
    auto lambda0_result = lambda0();
}
먼저 가장 간단한 람다 표현식의 형태를 소개한다. 람다식은 auto에 저장해두고 쓰면 된다. 예제의 람다식 `lambda0`는 아무런 매개변수 없이 반환문만 존재한다. 람다식을 사용할 때는 함수와 똑같이 ()를 붙여 실행할 수 있다.
#!syntax cpp
int main()
{
    // (2) 정수를 반환하는 람다 표현식
    auto lambda1 = [] -> unsigned long { return 10UL; };

    // `lambda1_result`는 10ul
    auto lambda1_result = lambda1();

    // (3) 실수를 반환하는 람다 표현식
    // 이 람다 표현식은 정수를 실수로 변환한다.
    auto lambda2 = [] -> double { return 10; };

    // `lambda2_result`는 10.0
    auto lambda2_result = lambda2();
}
대괄호 [] 뒤에 -> (화살표 연산자)와 함께 반환 자료형을 명시할 수 있다. `lambda1`의 경우 경우 내부의 반환문과 명시한 반환 자료형의 차이가 없다. `lambda2`는 반환 자료형을 내부의 반환문과 다르게 명시한 예시다. 이 경우엔 static_cast<double>로 변환되며 10.0을 반환한다.
#!syntax cpp
int main()
{
     std::string left{ "Left" };
     std::string right{ "Right" };

    // (4) auto로 인자를 받아서 더한 뒤 반환하는 람다 표현식
    auto lambda3 = [](auto lhs, auto rhs) -> auto { return lhs + rhs; };

    // const char[7]
    auto str = "Tail";

    // `lambda4_result_a`는 std::string
    // `lambda4_result_a`의 값은 "LeftTail"
    auto lambda3_result_a = lambda3(left, str);

    // `lambda4_result_b`는 std::string
    // `lambda4_result_b`의 값은 "HeadRight"
    auto lambda3_result_b = lambda3("Head", right);

    // (5) decltype으로 반환 자료형을 명시한 람다 표현식
    auto lambda4 = [](auto lhs, auto rhs) -> decltype(lhs + rhs) { return lhs + rhs; };

    // `lambda4_result`는 std::string{ "LeftRight" }
    auto lambda4_result = lambda4(left, right);
}
반환 자료형에는 일반 함수와 마찬가지로 autodecltype(expression)을 사용할 수 있다.
#!syntax cpp
int main()
{
    // (6) 반환형을 auto로 명시한 람다 표현식
    auto lambda5 = [](float lhs, auto rhs) -> auto { return lhs * rhs; };

    // `lambda5_result_a`는 float
    // `lambda5_result_a`의 값은 30.0f
    auto lambda5_result_a = lambda5(10.0f, 3.0f);

    // `lambda5_result_b`는 float
    // `lambda5_result_b`의 값은 50.0f
    auto lambda5_result_b = lambda5(0.5, 100);
}
상기 코드에서는 인자의 자료형과 매개변수의 자료형이 같은 경우와 다른 경우를 보여주고 있다.

여담으로 매개변수에 auto, decltype(auto), 템플릿 매개변수가 포함된 람다 표현식은 일반화된 람다식(Generic Lambda)이라고 부른다. 거창한 의미는 아니고 람다 표현식에서도 일반화 함수와 같은 맥락으로 특별하게 부르는 것이다.
#!syntax cpp
int main()
{
    // (7) 정수를 매개변수로 받아서 출력하는 람다 표현식
    auto lambda6 = [](int value) -> void { std::println(value); };

    // std::vector<int>
    std::vector list{ 0, 1, 2, 3, 4 };

    for (auto v : list)
    {
        lambda6(v);
    }
}
당연히 람다 표현식은 모든 종류의 함수를 실행할 수 있다.

상기한 예제에서 소개한 람다 표현식은 모두 일반적인 함수와 동일한 형태를 가지고 있다. 이 정도로는 람다 표현식의 유용함을 알기 어렵다. 다음에 소개할 람다 표현식은 상태를 가지고 있다. 상태가 무엇인지 알아보자.

2.1. 완벽한 매개변수 전달

#!syntax cpp
import <numeric>;

struct [[nodiscard]] Rational
{
    unsigned long long num = 0;
    unsigned long long den = 0;

    [[nodiscard]]
    friend constexpr Rational operator+(const Rational& lhs, const Rational& rhs)
    {
        const auto lcm = std::lcm(lhs.den, rhs.den);
        const auto ltm = lcm / lhs.den;
        const auto rtm = lcm / rhs.den;

        return Rational{ lhs.num * ltm + rhs.num * rtm, lcm };
    }

    friend constexpr Rational& operator+=(Rational& lhs, const Rational& rhs)
    {
        return (lhs = lhs + rhs);
    }

    [[nodiscard]]
    friend constexpr Rational operator*(const Rational& lhs, const Rational& rhs)
    {
        const auto num = lhs.num * rhs.num;
        const auto den = lhs.den * rhs.den;
        const auto gcd = std::gcd(num, den);

        return Rational{ num / gcd, den / gcd };
    }

    friend constexpr Rational& operator*=(Rational& lhs, const Rational& rhs)
    {
        return (lhs = lhs * rhs);
    }

    [[nodiscard]]
    constexpr operator double() const
    {
        return static_cast<double>(num) / static_cast<double>(den);
    }
};

int main()
{
    constexpr Rational left{ 1, 10 }; // 10분의 1
    constexpr Rational right{ 3, 7 }; // 7분의 3

    // (1) auto로 인자를 받아서 곱한 뒤 반환하는 람다 표현식
    constexpr auto lambda0 = [](auto lhs, auto rhs) -> auto { return lhs * rhs; };

    // `lambda0_result`는 Rational
    // `lambda0_result`의 값은 Rational{ 3, 70 };
    constexpr auto lambda0_result = lambda0(left, right);

    // (2) 완벽한 전달로 인자를 받아서 더한 뒤 반환하는 람다 표현식
    constexpr auto lambda1 = [](auto&& lhs, auto&& rhs) -> decltype(lhs += rhs) { return lhs += rhs; };
    // 상동
    constexpr auto lambda1_alt = [](auto&& lhs, auto&& rhs) -> decltype(auto) { return lhs += rhs; };

    Rational next{ 5, 9 };

    // (3) `lambda1_result`는 Rational&
    // `lambda1_result`의 값은 Rational{ 62, 63 };
    auto&& lambda1_result = lambda1(next, right);
}
람다 표현식에서도 완벽한 매개변수 전달을 수행할 수 있다. 상기 코드에서는 좌측값 참조자 &를 유지하면서 반환하는 람다 표현식을 보여주고 있다. 만약 완벽한 전달을 하지 않았더라면 Rational& 대신 Rational이 복사되어 반환됐을 것이다.

3. 람다 캡처

람다 포섭 (Lambda Capture)
람다 표현식을 선언할 때에는, 맨 처음 포섭란([] 대괄호) 안에 어떤 변수의 이름, &, =, 혹은 this를 넣어서 람다 표현식 내부에서 사용할 필드를 선정할 수 있다. 이때 선정된 변수는 함수 매개변수처럼 람다 표현식에서 복사, 이동, 참조될 수 있다. 포섭된 필드는 기본적으로 불변(const)인 것만 빼면 람다식 안에서 자유롭게 이용할 수 있다.

이때 참조자가 아닌 변수는 새로운 상수로 정의되면서 복사된다. 함수에 & 참조자를 쓰지 않으면 복사나 이동되는 것과 같은 경우다. 람다 표현식이라고 복잡한 무언가가 있는게 아니라 함수와 똑같으며, 다만 편의성을 위한 추가 문법을 지원하는 것이다.

이 기능이 존재하는 이유는 람다 표현식은 어떤 문맥[1]에 종속된 존재가 아니라, 하나의 객체로서 모든 곳에서 사용될 수 있어야 하기 때문이다. 그래서 람다 표현식 스스로가 상태를 가질 수 있는데, C++에서는 변수를 가져옴으로써 외부의 상태를 저장한다.

3.1. 복사 포섭

#!syntax cpp
short GetPort() noexcept
{
    return 10008;
}

int main()
{
    int i{ 5 };
    const int j{ 10 };

    // (1) 외부의 변수 `i`를 포섭. 이제 람다 표현식 안에서 `i`의 이름을 사용할 수 있다.
    [i] { std::println("`i` is {}", i); };

    // (2) 외부의 변수 `j`를 포섭. 포섭한 객체와 포섭 필드의 이름은 중복이어도 된다.
    [j = j] {};

    // (3) `i`를 이름 `integer_inside`로 포섭
    // `i = i` 처럼 람다 외부와 내부의 이름은 중복되어도 문제없음.
    // 포섭된 `integer_inside`와 `i`는 상수이므로 수정할 수 없음.
    auto lambda = [integer_inside = i, i = i] -> void {
        std::println("{}", i);
    };

    // (4) 변수 `i`를 포섭란에서 즉시 정의.
    [i = std::move(i)] {};

    // (5) 변수 `port`를 포섭란에서 즉시 정의.
    [port = GetPort()](std::string_view ip_address) {};
}
상기 예제에서는 복사 포섭 방법을 소개하고 있다. 포섭란에 변수의 이름을 기입하면 람다 표현식 내부로 그 변수를 가져온다. 복사 포섭된 필드는 이름대로 값이 복사된다.

3.2. 참조 포섭

#!syntax cpp
int main()
{
    int i = 1;

    // (3) `i`를 참조 포섭
    auto lambda2 = [&i] {
        std::println(i);

        // 람다 내부에서 `i`의 값은 4가 됨.
        i = 4;
    };
    lambda2();
    // 마찬가지로 람다 외부의 `i`의 값도 4가 됨.

    // (4) `i`를 이름 `integer_inside`로 참조 포섭
    auto lambda3 = [&integer_inside = i] {
        std::println("{}", integer_inside);

        // 람다 내부에서 `integer_inside`의 값은 5가 됨.
        integer_inside = 5;
    };
    lambda3();
    // 람다에서 외부의 `i`를 `integer_inside`로 참조했으므로 람다 외부의 `i`의 값도 5가 됨.
}
상기한 코드는 참조 포섭의 기작을 보여준다. 참조자로 포섭한 변수는 람다 표현식 내부에서 원본을 그대로 이용할 수 있다. 참조 포섭은 람다 표현식 내부에서 외부에 영향을 끼칠 수 있게 만든다.
#!syntax cpp
struct Squirrel
{
    int myAge;

    constexpr Squirrel(int age = 0) noexcept
        : myAge(age)
    {}
};

// `Squirrel` 벡터를 받아서 시작 나이부터 `Squirrel`들의 나이를 증분시키는 함수
void enumerate_squirrels(std::vector<Squirrel>& list, int age_begin) noexcept
{
    for (auto& squirrel : list)
    {
        squirrel.myAge = age_begin++;
    }
}

int main()
{
    // 10개의 `Squirrel` 인스턴스가 담긴 std::vector 지역 변수
    std::vector<Squirrel> everySquirrels { 10 };

    // (1) `everySquirrels`를 포섭
    auto lambda0 = [squirrels = everySquirrels](int age_begin) {
        // 컴파일 오류! `enumerate_squirrels`의 인자 `list`에서 형식 한정자가 삭제되었습니다.
        // 즉 `std::vector<Squirrel>&`를 받는 함수에 `const std::vector<Squirrel>&`가 전달되어서 실행할 수 없음.
        enumerate_squirrels(squirrels, age_begin);

        // 포섭된 `squirrels`는 상수이므로 수정할 수 없음.
    };
    lambda0(3);
    // 람다 외부에 정의된 `everySquirrels`는 변화 없음.

    // (2) `everySquirrels`를 참조 포섭
    // `everySquirrels`를 그대로 기입해도 문제없음.
    auto lambda1 = [&squirrels = everySquirrels, &everySquirrels](int age_begin) {
        enumerate_squirrels(squirrels, age_begin);
        // 람다 내부에서 `squirrels`에 들어있는 `Squirrel` 인스턴스들의 `myAge`가 수정됨.
    };
    lambda1(3);
    // 마찬가지로 람다 외부에 정의된 `everySquirrels`도 수정됨.
}
원시 자료형 말고도 모든 종류의 자료형을 포섭할 수 있다. 상기한 예제에서는 복잡한 구조체에 대하여 포섭을 쓰는 방법을 보여주고 있다.

람다 표현식은 이런 식으로 함수와 구별되는 특징으로 자신만의 데이터 멤버를 가지고 있다. 그러나 아직 매개변수를 쓰는 것과 차이가 없어보인다. 사실 당연한 것이, 람다 표현식은 함수와 호환성을 유지하면서 활용 범위를 늘리는 데에 목적이 있기 때문이다. 활용성 면에서 어떤 차이가 있는지 알아보자.

3.3. 기본사항 포섭

기본사항 포섭 (Capture Default)
포섭란에 &= 중 하나를 기입하면 람다 표현식이 선언된 문맥의 정보를 전부 포섭할 수 있다 [2]. 곧 람다 표현식이 만들어진 당시의 환경을 그대로 가져간다(Capture)는 뜻이다.
  • & 포섭은 현재 문맥을 참조형으로 포섭한다.
  • = 포섭은 현재 문맥을 불변한 상태[const]로 포섭한다.
이때 다른 변수의 이름을 추가로 기입하면 변수마다 별도의 포섭 방식을 적용할 수 있다.
#!syntax cpp
int main()
{
    // 지역 변수
    int i{ 10 };
    std::vector list{ 0, 1, 2, 3, 4 };

    // (1) 벡터 `list`를 참조 포섭, 변수 `i`를 참조 포섭
    // 벡터 `list`의 세번째 원소의 참조형을 반환하는 람다 표현식
    auto lambda0 = [&] -> decltype(auto) {
        return list.at(2);
    };

    // int& lambda0_result == 2
    auto&& lambda0_result = lambda0();

    // (2) 원래 '2'가 들어있었던 벡터 `list`의 세번째 원소에 '10'이 대입된다.
    // 벡터 `list`가 수정된다. list == { 0, 1, 10, 3, 4 }
    lambda0_result = 10;

    // (3) 벡터 `list`를 포섭, 변수 `i`를 포섭
    // 벡터 `list`의 네번째 원소를 반환하는 람다 표현식
    auto lambda1 = [=] -> decltype(auto) {
        return list.at(3);
    };

    // int lambda1_result == 3
    auto&& lambda1_result = lambda1();

    // (4) 벡터 `list`를 포섭, 변수 `i`를 참조 포섭
    auto lambda2 = [&, list] {
        // 포섭된 `list`는 상수이므로 수정할 수 없음.
        //list[1] = 60;

        // 람다 표현식 외부의 `i`에 '20'이 대입된다.
        i = 20;
    };
    lambda2();
    // 람다 표현식 외부의 벡터 `list`는 변화없음.
    // 람다 표현식 외부의 `i`가 수정됨.

    // (5) 벡터 `list`를 참조 포섭, 변수 `i`를 포섭
    auto lambda3 = [=, &list] {
        // 람다 표현식 외부의 `list`의 두번째 원소에 '100'이 대입된다.
        list[1] = 60;

        // 포섭된 `i`는 상수이므로 수정할 수 없음.
        //i = 10;
    };
    lambda3();
    // 람다 표현식 외부의 벡터 `list`가 수정됨.
    // 람다 표현식 외부의 `i`는 변화없음.
}
상기 예제는 기본사항 포섭이 작동되는 방식을 보여주고 있다. 일반 포섭과 참조 포섭이 혼용될 때 사례도 소개한다.

3.4. 클래스 인스턴스 포섭

람다 표현식에서 클래스의 인스턴스를 포섭할 수 있다. 이때 인스턴스.람다 표현식();의 용법은 안되지만 람다 표현식의 코드를 멤버 함수처럼 작성할 수 있다. 인스턴스를 포섭한 람다식은 클래스가 정의된 위치와 실행 시점에 구애받지 않고 어디에서나 자유롭게 호출할 수 있다. 즉 스코프 또는 함수에 종속되지 않는다.
  • &, =, this: 현재 문맥이 클래스의 인스턴스일 경우, 인스턴스의 모든 멤버를 참조형으로 포섭한다. 비정적 데이터 멤버에 대하여 참조 포섭을 사용하면 각각 다른 방법으로 포섭할 수 있다.
  • *this: 인스턴스를 불변 참조 포섭한다.
#!syntax cpp
struct Captured
{
    auto GetLambda()
    {
        return [this](int v) { MemberFunction(v) };
    }

    void MemberFunction(int v)
    {
        dataMember = v;
    }

    int dataMember;
};

int main()
{
    Captured instance;

    auto lambda = instance.GetLambda();
    lambda(5);
}
상기 코드는 인스턴스 포섭의 예시를 보여주고 있다.

이 기능의 유용함은 다수의 인스턴스를 중앙에서 관리하는 시스템을 구축할 때 드러난다. 예를 들어서 다중 스레드 환경, 하나의 파일을 클래스를 통해 관리하면서, 파일 인스턴스를 여러 곳에서 참조하고 싶지만 동적 할당이나 포인터를 쓰고 싶지 않을 때, 혹은 다수의 파일을 한번에 종합해서 관리하는 IO 작업, 게임에서 인스턴스를 관리하는 게임 관리자 클래스를 만들 때 등이 있다. 그외에 람다 표현식은 일반 전역 함수처럼 람다-표현식(...);의 형태로 호출할 수 있기 때문에 코드 호환성이나 심미적으로도 좋은 결과를 볼 수 있다.

3.5. 예제1: 스레드를 넘나드는 람다 표현식

#!syntax cpp
int main()
{
    auto finalizer = [](const std::thread::id& id) { std::println("스레드 {}에서 메시지 보냄.", id); };

    // `finalizer` 캡처
    auto awaiter = [finalizer](long long sec)
        {
            std::this_thread::sleep_for(std::chrono::seconds(sec));

            finalizer(std::this_thread::get_id());
        };

    std::jthread worker1{ awaiter, 3 };
    std::jthread worker2{ awaiter, 7 };
}
람다식은 어디에서나 사용할 수 있으며 심지어 다른 스레드에서도 마찬가지다. 포섭을 사용했어도 문제없다.

4. 포섭의 제한 사항

4.1. 정적 변수 사용

#!syntax cpp
// 전역 변수
int globalInteger;

int main()
{
    // 정적 변수
    static int staticInteger = 0;

    // (1) 전역 변수는 그대로 사용할 수 있다.
    auto lambda0 = [] { return globalInteger * 5; };

    // (2) 정적 변수는 그대로 사용할 수 있다.
    [] { staticInteger += 3; };

    // (3) 컴파일 오류! 정적인 지속 시간을 가진 객체는 캡처할 수 없습니다.
    [globalInteger] {};
}
정적인 지속요건을 가진(Static Duration) 변수는 포섭할 수 없다. 정적인 지속요건을 가진 변수에는 전역 변수, static 변수 등이 있다. 이런 변수들은 그냥 람다 표현식안에서 별다른 조치없이 그대로 사용할 수 있다.

4.2. 중복 포섭

#!syntax cpp
int main()
{
    int i;

    // (1) 컴파일 오류! 캡처 목록에서 하나의 이름이 여러번 표시될 수 없습니다.
    [i, i] {};

    // (2) 컴파일 오류! 캡처 목록에서 하나의 이름이 여러번 표시될 수 없습니다.
    [i, &i] {};

    // (3) 컴파일 오류! 캡처 목록에서 하나의 이름이 여러번 표시될 수 없습니다.
    [&i, &i] {};

    class Captured
    {
    public:
        void Method()
        {
            // (4) 컴파일 오류! 하나의 이름이 여러번 표시될 수 없습니다.
            [this, this] {};

            // (5) 컴파일 오류! 하나의 이름이 여러번 표시될 수 없습니다.
            [this, *this] {};
        }
    };
}
똑같은 객체[4]를 중복해서 캡처할 수 없다. 설령 아무 참조자도 넣지 않고 필드 이름을 넣어도 마찬가지다. 이 부분은 IDE 혹은 컴파일 시에 문제를 바로 확인할 수 있으므로 참고하라.

4.3. 참조 대상 소실

#!syntax cpp
int* value = new int{0};

// 참조 포섭
auto lambda = [&ref = *value] { ref = 30; };

// 참조 대상 소실
delete value;

// 런타임 오류! 메모리 참조 위반!
lambda();
또 하나 조심해야할 점은 참조 포섭의 경우 좌측값 참조자와 마찬가지로 하드 링크가 아니라는 것이다. this, &로 외부 환경을 통째로 참조 포섭한 경우도 마찬가지다. 언제나 참조 대상 소실 (Dangling Reference)이 발생할 수 있다는 점을 명심하고, 참조할 대상이 소멸하지 않을 게 확실할 때만 참조 포섭을 사용해야 한다. 또는 스마트 포인터 등의 도움이 있다면 문제가 발생할 지점을 미리 알고 예방할 수 있다.

5. 특성 적용

람다 표현식도 일반 함수와 마찬가지로 특성을 사용할 수 있다. 함수에 적용할 수 있는 특성이라면 모두 사용할 수 있다. 포섭 대괄호 []와 매개변수 소괄호 () 사이에 기입하면 된다.

그런데 실제로는 일회용으로 자주 쓰이는 람다 표현식에 쓰는 게 쓸만한지가 의문일 수 있다. 그래도 메모리를 할당하는 람다 표현식이라면 [[nodiscard]]를 적용하는 건 아주 좋은 선택이다.
#!syntax cpp
int main()
{
    auto allocator = [][[nodiscard]] (std::size_t length) { return new int[length]; };

    // (1) int[10]
    auto memory = allocator(10);

    // (2) 경고! 함수의 반환 값이 사용되지 않았습니다.
    allocator(100);
}
상기 예제는 매개변수로 메모리 길이를 받아서 정수 메모리를 동적 할당하는 람다 표현식을 보여주고 있다. 해당 사례에서는 [[nodiscard]]를 적용해서 동적 할당한 메모리를 실수로 놓치지 않도록 작성했다.

6. 상수 람다 표현식

C++17부터는 람다 표현식의 선언 시에 constexprC++17, constevalC++20을 사용할 수 있다. 그런데 람다 표현식이 상수 표현식의 조건을 만족하면 constexpr는 자동으로 붙는다. 일종의 문법적 설탕인 셈인데, 상수 표현식 함수에서 람다 표현식을 쉽게 쓸 수 있도록 한 안배로 보인다.
#!syntax cpp
constexpr auto Absolute = [] (auto value) { return 0 <= value ? value : -value; };
상기 예제는 절대값을 구하는 람다 표현식을 보여주고 있다.

7. 템플릿 람다 표현식

람다 표현식에도 템플릿을 사용할 수 있다.

그러나 읽기도 힘들고 편리한 auto가 전부 커버하므로 의의는 템플릿 매개변수를 직접 사용하는 데에 있다. 자료형을 가지고 메타 프로그래밍을 하려면 usingdecltype을 써서 매개변수의 자료형을 가져와야 하는데, 이게 귀찮으면 고려할 수도 있다. 그러나 람다 표현식은 함수와는 달리 템플릿 매개변수를 명시할 수가 없어서 무조건 함수 매개변수가 필요하므로 함수 매개변수를 위한 메모리 공간이 필요한 단점이 있다.
#!syntax cpp
// (1) 자료형의 크기에서 가까운 2의 배수를 구하는 람다 표현식
constexpr auto GetBlockSize = []<typename T> [[nodiscard]](const T&) noexcept -> std::size_t {
    constexpr std::size_t size = sizeof(T);
    constexpr std::size_t lower = size - (size % 2);
    constexpr std::size_t upper = lower + 2;
    return (size - lower < upper - size) ? lower : upper;
};

constexpr auto size_integer = GetBlockSize(0);
constexpr auto size_squirrel = GetBlockSize(Squirrel{});

// (2) 앞서 소개한 절대값을 구하는 람다 표현식을 템플릿을 써서 재정의한 람다 표현식
constexpr auto Absolute = []<typename T> [[nodiscard]] (const T& value) noexcept -> T {
    return 0 <= value ? value : -value;
};
상기 예제는 템플릿을 활용한 람다 표현식을 보여주고 있다.

8. 함수의 매개변수로 전달

람다 표현식은 상태를 가지면서 복사 가능하고, 이동 가능하고, 참조될 수 있다. 당연히 함수를 통해서도 가능하며 이쪽이 람다 표현식의 주 용법이라고 할 수 있다. 람다 표현식을 본격적으로 활용하려면 함수로 주고받는 방법을 알아야 한다. 실제 용법에서 람다 표현식을 만든 즉시 실행하는 경우는 템플릿과 활용하는 경우 몇몇을 빼면 거의 없으므로[5].
#!syntax cpp
int CalculateTenTime(int init, auto predicate)
{
    for (int i = 0; i < 10; ++i)
    {
        init = predicate(init);
    }

    return init;
}

// `val`의 값은 2048
int val = CalculateTenTime(2, [](int v) { return v * 2; });
지금까지 살펴본 예제에서는 람다 표현식을 모두 auto에 담아서 사용했다. 함수의 인자로 넣을 때도 마찬가지로 auto를 사용하면 된다. 주목할 점은 람다 표현식을 함수에 전달할 때 완벽한 매개변수 전달을 수행할 필요가 없다. auto&&를 쓰지 않고 그냥 auto로 전달해도 문제가 없다.
#!syntax cpp
auto GetMapper(auto& container, auto predicate)
{
	return [&] {
		for (auto& value : container)
		{
			value = predicate(value);
		}
	};
}

auto GetMapper(auto& container)
{
	return [&](auto predicate) {
		for (auto& value : container)
		{
			value = predicate(value);
		}
	};
}

[[nodiscard]]
constexpr int MultiplyFunction(int v) noexcept
{
	return v * 10;
}

int main()
{
	std::vector list{ 1, 2, 3, 4, 5 };

	// (1) 벡터 `list`를 참조형으로 받아서 수정하는 람다 표현식
	auto mapper0 = GetMapper(list, [](auto v) noexcept { return v * 10 });

	// `list`가 수정된다.
	// `list` == { 10, 20, 30, 40, 50 };
	mapper0();

	// (2) 상태가 없는 람다 표현식이므로 함수를 사용해도 같은 결과를 볼 수 있다.
	// 컴파일러가 릴리스 모드면 성능 상에 차이는 없다.
	auto mapper1 = GetMapper(list, MultiplyFunction);

	// (3) 수식 `predicate`를 복사로, 벡터 `list`를 참조형으로 받아서 수정하는 람다 표현식
	auto mapper2 = GetMapper(list);

	// `list`가 수정된다.
	// `list` == { 1, 2, 3, 4, 5 };
	mapper2([](auto v) noexcept { return v / 10; });
}
상기 코드는 벡터를 참조형으로 받아서 수정하는 람다 표현식을 보여주고 있다.
람다 표현식은 당연히 템플릿으로 받을 수 있다. 앞서 auto를 쓰는 방식과 똑같이 사용하면 된다.
#!syntax cpp
template<typename It, typename Predicate>
constexpr auto find_if(It first, It last, Predicate predicate)
{
    for(; first != last; ++first)
    {
        if (predicate(*first))
        {
            return first;
        }
    }

    return first;
}
상기한 코드는 표준 라이브러리find_if를 구현한 예제다. 이 함수는 템플릿으로 실행 가능한(invocable) 함수 객체(Function Object)를 받아서 순회자의 값을 인자로 전달하고, 순회자의 값을 통해 실행시켜서 조건을 만족하는 순회자를 찾는 함수다.

만약 써본 경험이 있다면 알겠지만 이 함수에는 일반적인 함수, () 연산자를 오버로딩한 클래스, 람다 표현식 모두를 전달할 수 있다.

여기까지가 C++을 어플리케이션에서 활용하고자 하는 사람의 최종 단계다. 이제 심화 내용으로 넘어가며 필요에 의해 배우면 된다. 여기까지 이해했다면 C++에서 문법적 기능은 거의 다 숙지했다고 볼 수 있으며 어플리케이션을 제작하는 단계에서는 굳이 필요한 내용은 아니다. 하지만 라이브러리 혹은 프로젝트 내부에서 유틸리티를 제작할 때 유용한 내용이다.

8.1. 개념 (Concept) 매개변수로 전달

템플릿에 제약조건을 걸어서 받을 수 있는 자료형을 제한할 수 있다.
#!syntax cpp
import <type_traits>;
import <concepts>; // std::sentinel_for, std::invocable
import <iterator>; // std::forward_iterator, std::iter_value_t
import <functional>; // std::invoke
import <vector>; // std::vector
import <ranges>; // std::from_range_t, std::from_range, std::views::iota

template<std::forward_iterator It, std::sentinel_for<It> Sentinel>
constexpr It find_if(It first, const Sentinel last, std::invocable<std::iter_value_t<It>> auto predicate)
{
    for (; first != last; ++first)
    {
        if (std::invoke(predicate, *first))
        {
            return first;
        }
    }

    return first;
}

int main()
{
    const std::vector list{ std::from_range, std::ranges::views::iota(1, 10) };

    // 3으로 나누어 나머지가 0인 값이면 참을 반환
    const auto it = ::find_if(list.begin(), list.end(), [](const auto& value) noexcept -> bool { return value % 3 == 0; });

    // `what`의 값은 3
    auto what = *it;

    // `write_bytes`는 int, int, double& 매개변수를 받아 실행할 수 있는 람다 표현식
    std::invocable<int, int, double&> auto write_bytes = [](int left, int right, double& dest) noexcept {
        *(reinterpret_cast<int*>(&dest) + 1) = left;
        *(reinterpret_cast<int*>(&dest)) = right;
    };

    double storage{};
    write_bytes(4000, 3000, storage);
}
상기 코드는 앞서 소개한 find_if를 한번 더 엄밀하게 정의한 버전을 보여주고 있다. 그리고 개념과 auto를 조합하여 람다 표현식을 선언한 예시도 보여주고 있다.

9. 함수 포인터로 변환

#!syntax cpp
int main()
{
    // 실수를 반환하는 람다 표현식
    auto lambda = [] { return 1.0; };

    // 상태를 가지고 있지 않은 람다 표현식은 함수 포인터에 저장이 가능하다.
    // 후술하겠지만 decltype(lambda)은 클로저의 자료형을 반환하므로 주의.
    using lambda_t = double(*)();
    lambda_t lambda_v = lambda;
}
포섭한 변수를 가지고 있지 않은 람다 표현식은 함수 포인터로 형변환할 수 있다. 반대로는 불가능하다.
#!syntax cpp
import <type_traits>;

// 함수
int Function0() { return 0; }
int Function1() noexcept { return 0; }
template<typename T> T Function2(T value) { return T * T; }

// 함수 포인터 자료형 선언
using Function0_t = int(*)();
using Function1_t = int(*)();
using Function1_nothrow_t = int(*)() noexcept;
template<typename T>
using Function2_t = T(*)(T value);

// 람다 표현식
auto lambda0 = [] { return 0; };
auto lambda1 = [] { return 0; };
auto lambda1_nothrow = [] noexcept { return 0; };
auto lambda2 = []<typename T>(T value) -> T { return value * value; };

using lambda0_t = decltype(lambda0);
using lambda1_t = decltype(lambda1);
using lambda1_nothrow_t = decltype(lambda1_nothrow);
using lambda2_t = decltype(lambda2);

// (1) 컴파일 오류! 정적 어설션이 실패했습니다.
static_assert(std::is_same_v<Function0_t, lambda0_t>);
static_assert(std::is_same_v<Function1_t, lambda1_t>);
static_assert(std::is_same_v<Function1_t, lambda1_nothrow_t>);
static_assert(std::is_same_v<Function2_t<int>, lambda2_t>);

// (2) 컴파일 오류 없음.
// 상태가 없는 람다 표현식은 동일 매개변수, 동일한 반환 자료형, 동일한 예외 상세(C++17 부터)를 갖고 있으면 함수 포인터로 변환이 가능함.
static_assert(std::is_convertible_v<lambda0_t, Function0_t>);
static_assert(std::is_convertible_v<lambda1_t, Function1_t>);
static_assert(std::is_convertible_v<lambda1_nothrow_t, Function1_nothrow_t>);
// `lambda2_t`는 템플릿 람다 표현식인데, 템플릿 매개변수를 명시할 수가 없어서 우회해서 원래의 멤버 함수를 가져와야 함.

// (3) C++17 부터는 동일한 예외 명세를 가져야 상호 변환이 가능함.
// C++14 까지는 어설션이 성공함.
// C++17 부터는 컴파일 오류 발생함.
static_assert(std::is_convertible_v<lambda1_t, Function1_nothrow_t>);

// (4) noexcept 함수 포인터는 예외를 발생시킬 수 있는 함수 포인터로 변환할 수 있음.
static_assert(std::is_convertible_v<Function1_nothrow_t, Function1_t>);

int main()
{
    // (5) 상태가 없는 람다 표현식은 상수 시간에 초기화될 수 있음.
    constexpr lambda2_t lambda2_inst{};

    // (6) 람다 표현식의 멤버 연산자 함수
    // int에 대하여 특수화함.
    const auto lambda2_op_ptr = &(lambda2_t::operator()<int>);

    // (7) `lambda2_result`의 값은 400
    const auto lambda2_result = (lambda2_inst.operator())(20);
}
상기 코드는 상태가 없는 람다 표현식과 함수 포인터 사이의 관계를 보여주고 있다.

마지막으로 람다 표현식의 동작이 어떻게 이루어지는지 살펴보자. 람다 표현식도 C++의 구성에서 완전히 동떨어진 존재가 아니다.

10. 정체

클로저 (Closure)
람다 표현식은 템플릿과 __func__ 매크로도 쓸 수 있는 등 겉보기에는 함수와 다르지 않다. 하지만 람다 표현식은 함수 포인터가 아니며 상태를 가지고 있으면 함수 포인터 변수에 담을 수 없다. 람다 표현식의 정체는 바로 () 연산자를 오버로딩한 클래스의 인스턴스다. 즉 람다 표현식도 함자(Functor) 또는 함수 객체(Function Object)이며, 포섭한 필드는 이 인스턴스의 데이터 멤버로 정의되는 것이다.

한편 파생되는 특징 중 하나는 인자 의존성 탐색이 일어나지 않는다는 점인데 이에 대해서는 여기선 다루지 않겠다.

10.1. 상태가 없는 클로저

#!syntax cpp
class StatelessClosure
{
    using Fn = ReturnType(*)(parameters...);

public:
    constexpr StatelessClosure() = default;
    constexpr ~StatelessClosure() = default;

    /* 기본 복사/이동 생성자를 가짐 */
    constexpr StatelessClosure(const StatelessClosure&) = default;
    constexpr StatelessClosure(StatelessClosure&&) = default;

    /* 기본 복사/이동 대입 연산자를 가짐 */
    constexpr StatelessClosure& operator=(const StatelessClosure&) = default;
    constexpr StatelessClosure& operator=(StatelessClosure&&) = default;

    /* () 연산자 오버로딩 */
    constexpr ReturnType operator()(parameters...);

    /* 함수 포인터로 변환할 수 있음 */
    constexpr operator Fn() const noexcept;

private:
    // 포섭된 필드가 없음.
};
상기 코드는 포섭된 필드가 없는 단순한 람다 표현식 클래스를 보여주고 있다. 함수 포인터로 변환할 수 있으며 생성/대입에서 복사/이동이 자유롭다.

10.2. 상태가 없는 일반화 클로저

#!syntax cpp
class StatelessGenericClosure
{
    template<typename... Ts>
    using Fn = ReturnType(*)(Ts... parameters);

public:
    constexpr StatelessGenericClosure() = default;
    constexpr ~StatelessGenericClosure() = default;

    /* 기본 복사/이동 생성자를 가짐 */
    constexpr StatelessGenericClosure(const StatelessGenericClosure&) = default;
    constexpr StatelessGenericClosure(StatelessGenericClosure&&) = default;

    /* 기본 복사/이동 대입 연산자를 가짐 */
    constexpr StatelessGenericClosure& operator=(const StatelessGenericClosure&) = default;
    constexpr StatelessGenericClosure& operator=(StatelessGenericClosure&&) = default;

    /* () 연산자 오버로딩 */
    template<typename... Ts>
    constexpr ReturnType operator()(Ts... parameters);

    /* 함수 포인터로 변환할 수 있음 */
    template<typename... Ts>
    constexpr operator Fn<Ts...>() const noexcept;

private:
    // 포섭된 필드가 없음.
};
상기 코드는 템플릿 혹은 auto를 사용한 일반화된 람다 표현식(Generic Lambda Expression)의 클래스를 보여주고 있다. 함수 포인터로 변환할 수 있으며 마찬가지로 복사/이동 생성/대입이 자유롭다.

10.3. 상태를 가진 클로저

#!syntax cpp
class Closure
{
public:
    /* 기본 생성자를 가지고 있지 않음. 람다 표현식 인스턴스가 생성될 때 결합(Aggregate) 생성 방식으로 전달됨. */
    // constexpr Closure() = default;
    constexpr ~Closure() = default;

    /* 기본 복사/이동 생성자를 가짐 */
    constexpr Closure(const Closure&) = default;
    constexpr Closure(Closure&&) = default;

    /* 복사 대입 연산자는 삭제됨 */
    Closure& operator=(const Closure&) = delete;
    /* 이동 대입 연산자는 컴파일러에 의해 알아서 정의됨 */
    /* 참조 포섭을 했으면 좌측값 참조 데이터 멤버가 있으므로 이동 대입 연산자가 정의되지 않음 */
    //Closure& operator=(Closure&&) = default;

    /* () 연산자 오버로딩 */
    constexpr ReturnType operator()(parameters...);

    /* 함수 포인터로 변환은 불가능함 */
    //using Fn = ReturnType(*)(parameters...);
    //constexpr operator Fn() const noexcept;

private:
    // 포섭된 필드는 데이터 멤버임.
    T0 capture0;
    T1 capture1;
    // ...
};
상기 코드는 상태를 가진 람다 표현식의 클래스를 보여주고 있다. 포섭한 변수는 클래스의 데이터 멤버로 포함된다. 인스턴스의 생성은 집결 초기화(Aggregate Initialization)로 수행된다. 복사 대입은 불가능하며 이동 대입의 경우 좌측값 참조자 데이터 멤버가 없으면 가능하다.

10.4. 상태를 가진 일반화 클로저

#!syntax cpp
class GenericClosure
{
public:
    /* 기본 생성자를 가지고 있지 않음. 람다 표현식 인스턴스가 생성될 때 집결 초기화(Aggregate Initialization) 방식으로 전달됨. */
    // constexpr GenericClosure() = default;
    constexpr ~GenericClosure() = default;

    /* 기본 복사/이동 생성자를 가짐 */
    constexpr GenericClosure(const GenericClosure&) = default;
    constexpr GenericClosure(GenericClosure&&) = default;

    /* 복사 대입 연산자는 삭제됨 */
    GenericClosure& operator=(const GenericClosure&) = delete;
    /* 이동 대입 연산자는 컴파일러에 의해 알아서 정의됨 */
    /* 참조 포섭을 했으면 좌측값 참조 데이터 멤버가 있으므로 이동 대입 연산자가 정의되지 않음 */
    //GenericClosure& operator=(GenericClosure&&) = default;

    /* () 연산자 오버로딩 */
    template<typename... Ts>
    constexpr ReturnType operator()(Ts... parameters);

    /* 함수 포인터로 변환은 불가능함 */
    //template<typename... Ts> using Fn = ReturnType(*)(Ts... parameters);
    //template<typename... Ts> constexpr operator Fn<Ts...>() const noexcept;

private:
    // 포섭된 필드는 데이터 멤버임.
    T0 capture0;
    T1 capture1;
    // ...
};
상기 코드는 상태를 가진 일반화된 람다 표현식의 클래스를 보여주고 있다. 포섭한 변수는 클래스의 데이터 멤버로 포함된다. 인스턴스의 생성은 집결 초기화로 수행된다. 역시 복사 대입은 불가능하며 이동 대입의 경우 좌측값 참조자 데이터 멤버가 없으면 가능하다.

11. 둘러보기


||<:><-12><width=90%><tablewidth=100%><tablebordercolor=#20b580><rowbgcolor=#090f0a,#050b09><rowcolor=#d7d7d7,#a1a1a1>C++||||
C언어와의 차이점학습 자료평가
<bgcolor=#20b580>
<rowcolor=#090912,#bebebf>C++ 문법
<bgcolor=#ffffff>
main헤더모듈
함수구조체이름공간
한정자참조자포인터
클래스값 범주론특성
autousingdecltype
상수 표현식람다 표현식객체 이름 검색
템플릿템플릿 제약조건메타 프로그래밍
<bgcolor=#20b580>
<rowcolor=#090912,#bebebf>C++ 버전
<bgcolor=#ffffff>
C++26C++23C++20
C++17C++14C++11
C++03C++98C with Classes
<bgcolor=#20b580>
<rowcolor=#090912,#bebebf>C++ 표준 라이브러리
<rowcolor=#090912,#bebebf>문서가 있는 모듈 목록
<bgcolor=#ffffff>
#개요C++11 #개요<unordered_map>C++11 #개요
C++20 #개요#개요#개요
C++11 #개요C++11 #개요C++17 #개요
#개요<string_view>C++17 #개요C++20 #개요
C++11 #개요C++11 #개요C++11 #개요
C++20 #개요C++23 #개요
<bgcolor=#20b580>
<rowcolor=#090912,#bebebf>예제 목록
<bgcolor=#ffffff>
{{{#!wiki style=""text-align: center, margin: 0 -10px"
{{{#!folding [ 펼치기 · 접기 ]
임계 영역과 경쟁 상태
std::mutex
개선된 스레드 클래스
std::jthread
동시성 자료 구조 1
스레드 안전한 구현
동시성 자료 구조 2
스레드 안전한 집합 구현
메모리 장벽
std::atomic_thread_fence
스레드 상태 동기화 1
스레드 대기와 기상
원자적 메모리 수정
std::compare_exchange_strong
스레드 상태 동기화 2
스핀 락 구현
함수 템플릿
일반화 프로그래밍
전이 참조
완벽한 매개변수 전달
튜플 구현
가변 클래스 템플릿
직렬화 함수 구현
템플릿 매개변수 묶음
SFINAE 1
멤버 함수 검사
SFINAE 2
자료형 태그 검사
SFINAE 3
메타 데이터
SFINAE 4
자료형 트레잇
제약조건 1
개념 (Concept)
제약조건 2
상속 여부 검사
제약조건 3
클래스 명세 파헤치기
제약조건 4
튜플로 함자 실행하기
메타 프로그래밍 1
특수화 여부 검사
메타 프로그래밍 2
컴파일 시점 문자열
메타 프로그래밍 3
자료형 리스트
메타 프로그래밍 4
안전한 union
}}}
}}}||
<bgcolor=#20b580>
<rowcolor=#090912,#bebebf>외부 링크
<bgcolor=#ffffff>
{{{#!wiki style=""text-align: center, margin: 0 -10px"파일:홈페이지 아이콘.svg C++ 표준 위원회파일:홈페이지 아이콘.svg ISO C++ 표준파일:홈페이지 아이콘.svg C++ 표준 현황파일:홈페이지 아이콘.svg 공식 안내서
파일:홈페이지 아이콘.svg 참고서 위키파일:홈페이지 아이콘.svg 표준 헤더파일:홈페이지 아이콘.svg 컴파일러 지원파일:홈페이지 아이콘.svg C++ 위키백과
파일:홈페이지 아이콘.svg C++ 라이브러리파일:홈페이지 아이콘.svg C++ 패키지 관리자파일:홈페이지 아이콘.svg Boost파일:홈페이지 아이콘.svg 비야네 스트로스트룹의 홈페이지
}}}||
<bgcolor=#20b580>
<rowcolor=#090912,#bebebf>C++



[1] 예를 들어서 어떤 함수 또는 어떤 클래스[2] 둘 중 하나만 기입할 수 있다[const] [4] 필드, 필드의 참조형, this[5] 일반화 프로그래밍 분야에서 코드 재사용성을 극단으로 올리고자할 때 유용하다