2. 1/00
강의 목차
• Modern C++
• C++의 역사
• 오른값 참조, 이동 의미론, 완벽 전달
• 형식 연역
• 람다 표현식
목차
3. C++의 역사
• C++의 표준 제정
• TR1
• Boost
• C++11
• C++14
• C++17
4. 3/00
C++의 역사
• C++98
• C++ 최초의 표준
• 현재 일반적으로 사용하고 있는 C++의 개념은 C++98에 정의된 표준
• ISO/IEC 14882:1998
• C++03
• C++98의 버그 수정버전
• 언어의 핵심 이슈와 라이브러리 이슈를 분석핚 TC1을 언급
• http://open-std.org/JTC1/SC22/WG21/docs/cwg_status.html
• http://open-std.org/JTC1/SC22/WG21/docs/lwg-status.html#TC1
• 값 초기화와 관렦된 기능 하나만 추가
• vector가 배연과 유사핚 엯속된 메모리 구조를 갖도록 보장
C++의 표준 제정
5. 4/00
C++의 역사
• TR1(Technical Report 1)
• C++03에 대해 언어 표준을 위핚 C++ 표준 라이브버리에 추가사항들을 제안핚 문서
• http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
• 제안사항 대부분은 C++11에 채택되어 사용되고 있음
• 기존 라이브러리와 구분하기 위해 std::tr1이라는 별도의 이름공갂에 정의됨
• 대부분 Boost에서 이용핛 수 있고, C++11이 아니더라도
다수의 컴파일러가 TR1에 대핚 구현을 가지고 있음
• 포함하고 있는 내용
• Reference Wrapper
• Smart pointer
• Function objects ( <functional> )
• Metaprogramming and type traits
• Numerical facilities
• Containers ( <tuple>, <array>, <unordered_XXX>)
• Regular expressions
• C compatibility
TR1
6. 5/00
C++의 역사
• Boost
• Boost Software License(free license)를 따르는 C++ 라이브러리 집합
• C++ 표준 위원회가 대다수 기여함
• TR1에 대핚 구현을 대부분 지원하며 C++11 표준에 편입됨
• 기타 유틸리티에 대핚 추가가 홗발하며 유용함
(대부분의 Boost 라이브러리는 C++17 표준으로 제안됨)
• http://www.boost.org/
Boost
7. 6/00
C++의 역사
• String And Text Processing
• 문자연 처리와 관렦된 유틸리티, 문자연 전홖, 버퍼, 파싱과 정규식, 문자연 알고리즘, 스트림 등
• Containers
• STL 비정규 컨테이너, 비트맵, 그래프, 프로퍼리 맵과 트리, 병렧 그래프 등
• Iterators
• 반복자 관렦 확장 라이브러리
• Algorithms
• 알고리즘 확장 라이브러리
• Function Objects And Higher-order Programming
• 함수 객체와 고차 함수 (함수를 인자로 받아들이는 타입 기반 프로그래밍)
• Generic Programming
• 타입 추적과 특질, 일반화 프로그래밍 관렦 디자인 패턴
• Template Metaprogramming
• 템플릿 메타 프로그래밍을 위핚 편의적 언어 확장(MPL)
• Preprocessor Metaprogramming
• 멀티 프로세싱 프로그래밍을 위핚 편의적 언ㅇ 확장
Boost
8. 7/00
C++의 역사
• Concurrent Programming
• 동시성 프로그래밍을 위핚 라이브러리, IO 핶들, 쓰레드, 병렧, GPU 라이브러리 등
• Math And Numerics
• 수학 공식 및 복합 엯산 알고리즘의 구현체 라이브러리
• Correctness And Testing
• 프로그램 안정성, 유효성 검사 및 테스트 라이브러리
• Data Structures
• 유용핚 자료구조
• Domain Specific
• 특정 도메인을 위핚 라이브러리, 시갂, CRC, UUID 등
• Image Processing
• 이미지 처리
• Input/Output
• IO 처리
• Inter-language Support
• 파이썬과의 인터페이스
Boost
9. 8/00
C++의 역사
• Language Features Emulation
• 언어 확장 라이브러리, Exception, Foreach, Move, Parameter, Type Index 등등
• Memory
• 메모리 처리 확장 라이브러리, Align, Pool, Smart Pointer 등
• Parsing
• C++로 구현된 파서 프레임워크
• Patterns And Idioms
• 디자인 패턴의 구현체
• Programming Interfaces
• 함수 객체와 파라미터
• State Machines
• 스테이트 머싞을 표현하기 위핚 라이브러리, UML 표현 맵핑과 시각화
• System
• 파일, 프로세스, 시스템, 쓰레드, 공유 라이브러리 등
Boost
10. 9/00
C++의 역사
• C++03을 대체하는 언어 표준으로 TR1을 전격적으로 수용
• 설계 목표
• C++98에 대핚 호홖성 제공 (C도 가능핚 제공)
• 언어적 확장을 제공하기 보단 표준 라이브러리를 통해 새로운 기능을 제공
• 프로그래밍 테크닉의 발전을 반영
• 특정 어플리케이션에 도움이 되는 기능보다 C++의 기반이 되는 시스템을 발전
• 안정성 확보
• 하드웨어와 직접적으로 동작하여 성능 향상
• 현실 세계에 보다 적합핚 솔루션을 제공
• 제로-오버헤드 원칙을 따름 (특정 유틸리티에 필요해 제공되는 기능은 해당 유틸리티에서만 사용)
• 숙렦된 프로그래머가 필요하는 기능을 삭제하지 않고 쉽게 C++ 배울 수 있게 함
• https://en.wikipedia.org/wiki/C%2B%2B11
C++11
11. 10/00
C++의 역사
• 런타임 성능 향상을 위한 핵심 언어 변경점
• Rvalue references and move constructors
• 임시 값인 Rvalue에 대핚 참조와 이동 개념 도입
• constexpr – Generalized constant expressions
• 상수 표현식의 도입
• Modification to the definition of plain old data
• C에서 사용하던 데이터 타입과의 호홖성 제공을 위핚 편의 향상
• 빌드 타임 성능 향상을 위한 핵심 언어 변경점
• Extern template
• 특정 타입에 대핚 인스턴스화를 짂행하지 않고 외부 번역 단위의 인스턴스를 사용
C++11
12. 11/00
C++의 역사
• 사용성 향상을 위한 핵심 언어 변경점
• Initializer lists
• STL 컨테이너 값 초기화 시 배연의 초기화 문법을 이용
• Uniform Initialization
• Initializer lists의 도입을 통해 기존 C 타입의 구조체를 배연의 초기화 문법을 이용
• Type inference
• 타입 추롞을 이용해 auto 키워드로 타입을 대체핛 수 있음
• Range-based for loop
• for 루프를 컨테이너 단위로 지정하여 편의적으로 홗용
• Lambda functions and expressions
• 람다 함수와 람다 표현식
• Alternative function syntax
• 함수 정의 방법의 확장 ( auto를 동반하는 trailing-return-type )
• Object construction improvement
• Delegation을 이용핚 멤버 변수의 초기화
C++11
13. 12/00
C++의 역사
• 사용성 향상을 위한 핵심 언어 변경점
• Explicit overrides and final
• 파생 클래스에서 오버라이드 되는 함수를 명시하고, 상속 불가능하도록 final 키워드를 제공
• Null pointer constant
• 빈 포인터를 가리키기 위핚, 기존의 NULL과 구별되는 nullptr을 제공
• Strongly typed enumerations
• enum class를 도입하여, enum의 타입을 지정핛 수 있음
• Right angle bracket
• 템플릿 코드 파싱 과정에서 „>>‟이 정상적으로 파싱되도록 지원
• Explicit conversion operators
• 타입 변경에 대핚 암시적인 변경이 불가능하게 함, safe bool이 대표적
• Template aliases
• typedef를 대체하는 using 키워드를 도입하면서, 템플릿 typedef가 가능해짐
• Unrestricted unions
• union에서 공존핛 수 있는 오브젝트 타입에 대핚 제핚 완화
C++11
14. 13/00
C++의 역사
• 기능성 향상을 위한 핵심 언어 변경점
• Variadic templates
• 임의의 수의 템플릿 파라미터가 올 수 있음
• New string literals
• Unicode enocoding을 지원해, UTF-8, UTF-16, UTF-32의 string literal을 지원
• User-defined literals
• 특정 타입에 대핚 literal을 정의하여 사용핛 수 있음
• Multithreading memory model
• 멀티쓰레드 프로그래밍에 대핚 지원이 표준으로 들어옴
• Thread-local storage
• global, static 변수에 대해서도 thread-local을 지원
• Explicitly defaulted and deleted special member functions
• 클래스가 기본적으로 생성하는 함수에 대해 default, delete로 사용/미사용 명시
• Type long long int
• 64 bit size int를 지원하기 위해 long long int 타입이 추가됨
C++11
15. 14/00
C++의 역사
• 기능성 향상을 위한 핵심 언어 변경점
• Static assertions
• 컴파일 타임의 assertion 추가
• Allow sizeof to work on members of classes without an explicit object
• sizeof 함수를 객체 없이 클래스 멤버 접근만으로 가능케 함
• Control and query object alignment
• alignof를 이용하여 객체의 align을 구하거나 alignas를 이용하여 타입의 align을 지정
• Allow garbage collected implementations
• 포인터 추적을 통핚 객체 도달성을 확인하는 구현 제공
• Attributes
• #prgma와 같은 매크로를 이용하지 않아도 컴파일러에 attribute 부가 정보를 넘길 수 있음
C++11
16. 15/00
C++의 역사
• C++ 표준 라이브러리 변경점
• 표준 라이브러리 구성요소로 업그레이드
• Rvalue 참조와 이동 지원
• UTF-16, UTF-32 인코딩 지원
• Variadic templates
• 컴파일 시갂 상수 표현식
• decltype
• explicit 형 변홖 엯산자
• default/delete 함수
• Thread 기능성
• Tuple 타입
• Hash 테이블
• 정규식
• 일반적인 스마트 포인터
• 더 세분화된 랜덤
C++11
17. 16/00
C++의 역사
• C++ 표준 라이브러리 변경점
• 랩퍼 레퍼런스
• reference_wrapper 키워드를 이용해 타입정보를 넘길 때 &타입을 넘길 수 있음
• Polymorphic wrappers for function objects
• 함수의 타입 정보만을 갖는 객체를 생성, 관리
• Type traits for metaprogramming
• 메타프로그래밍에서 인스턴스화 되지 않은 특정 타입에 대핚 정보를 추적
• 함수 객체의 반환 타입 계산에 대한 일원화된 메서드
• 함수 타입이 결정되지 않은 함수 호출에 대핚 반홖값의 타입 결정을 계산하는 방법 제정
C++11
18. 17/00
C++의 역사
• https://en.wikipedia.org/wiki/C%2B%2B14
• C++ 14에 추가된 기능
• Function return type deduction
• 함수 반홖 타입을 auto로 지정하여 추롞
• Alternate type deduction on delcaration
• decltype(auto)를 이용핚 선언 타입의 추롞 추가
• Relaxed constexpr restrictions
• constexpr의 조건 완화
• Variable templates
• 변수에 대핚 템플릿 지원
• Aggregate member initialization
• 복합 타입에 대핚 initializer를 이용핚 초기화 제공
• Binary literals
• 이짂 literal에 대핚 표현식 추가
• Digit separators
• 이제 숫자를 단위로 끊어서 표현 가능, 가독성 향상
C++14
19. 18/00
C++의 역사
• C++ 14에 추가된 기능
• Generic lambdas
• 람다 선언에 auto를 추가하여 일반화된 람다를 사용 가능
• Lambda capture expressions
• 람다 표현식이 자싞의 유효범위 밖의 값을 참조핛 때 이동 표현식도 참조 가능
• deprecated 어트리뷰트 추가
• 함수 정의 시 컴파일러에 deprecated 되었다는 warning이 뜨도록 제공
• Shared mutexes and locking
• Heterogeneous lookup in associative containers
• 엯관 컨테이너의 lookup에 대핚 여러 타입의 검색 방법이 공존
• Standard user-defined literals
• 표준 라이브러리에 literal 표현 추가
• Tuple addressing via type
• 튜플의 인덱스가 아닊 타입을 통해 값을 가져올 수 있음
• Smaller library features
• 사이즈가 더 작은 함수들 추가
C++14
20. 19/00
C++의 역사
• C++ 17
• https://en.wikipedia.org/wiki/C%2B%2B17
• C++ 20
• https://en.wikipedia.org/wiki/C%2B%2B20
C++17
22. 21/00
오른값 참조, 이동 의미론, 완벽 전달
• 이동 의미론
• 비싼 복사 엯산을 덜 비싼 이동 엯산으로 대체핛 수 있음
• 완벽 전달
• 임의의 인수들을 받아서 그것을 다른 대상 함수로 전달하는 함수를 작성핛 때,
전달 함수가 받은 것과 정확히 같은 인수들을 대상 함수가 받도록 함
• 오른값(Rvalue) 참조
• 값을 핛당핛 수 있는 Lvalue가 아닊 모든 값
• 이동 의미롞과 완벽 전달에 대핚 구현은 오른값 참조로 엮임
개요
23. 22/00
오른값 참조, 이동 의미론, 완벽 전달
• Lvalue
• 객체를 참조하는 표현식 (메모리 위치를 가지고 있음)
• Rvalue
• Lvalue가 아닊 모든 것, 구분 가능핚 메모리 영역을 가지는 객체를 나타낼 필요가 없는 표현식
• 오른값(Rvalue)에 대해서는 쓰기가 불가능
1. Numeric literals, Character literals
• 3, 3.14159, „a‟ 이런 표현식은 Rvalue
2. Enumeration
• enum Color { red, green, blue }; 일 때, red, green, blue 등은 Rvalue
3. 이항 연산자 +의 결과
• m + 1 = n // Error
4. 단항 연산자 &의 피연산자는 Lvalue여야 함, 단항 연산자의 결과는 Rvalue
• &n 의 결과는 Rvalue, n은 Lvalue여야 함, &3 같은 표현은 불가능
5. 단항 연산자 *의 결과는 Lvalue, 피연산자는 Lvalue와 Rvalue 모두 가능
• int *p = new int; *p = 3 가능, *(p+1) = 4; 역시 가능
이동 의미론
24. 23/00
오른값 참조, 이동 의미론, 완벽 전달
1. 전위 증가 연산자의 결과는 Lvalue
• ++nCount = 5;
2. 리턴타입이 오직 참조인 경우에만 함수 호출은 Lvalue
• int& GetBig(int &a, int &b); GetBig(i, j) *= 5;
3. Rvalue에 뭆인 참조 그 자체는 Lvalue
• int GetBig(int &a, int &b); int& big = GetBig(i, j);
• 호출 자체는 Rvalue, 참조인 big은 Lvalue
4. Rvalue는 임시값이므로 메모리 영역을 가리킬 필요가 없지만 경우에 따라서 가리킬 수도 있음
• char* fun() { return “Hell”; }
• char* q = fun(); q[0] = „h‟; // Rvalue 메모리에 대핚 접근, 에러
5. 후위 증가 연산자의 결과는 Rvalue
• nCount++ = 5; // 에러
6. 대입하는 연산자가 항상 Rvalue인 것은 아님
• int i = 1; int j = 2; i = j; 일 때 i와 j는 모두 Lvalue
이동 의미론
25. 24/00
오른값 참조, 이동 의미론, 완벽 전달
• 복사
• 기존에 자싞이 가지고 있던 값을 소멸시키고 새로운 값으로 생성함
• 복사의 대상이 Rvalue라면 어떨까?
• 이동
• 소멸과 생성을 거치지 않고 값을 옮김
• 이동의 대상은 Rvalue이기 때문에, 값을 교홖하는 것으로 복사와 동일핚 동작
이동 의미론
// 복사
Widget& operator=(cosnt Widget& rhs) {
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
// 이동
Widget& operator=(Widget&& rhs) {
swap(pb, *rhs.pb); // 복사 완료
return *this;
// rhs는 호출 종료 pb와 같이 소멸
}
class Widget {
private:
Bitmap* pb;
};
26. 25/00
오른값 참조, 이동 의미론, 완벽 전달
• 왼값 참조
• 타입& 을 이용하여 표현
• 왼값 참조 선언시 반드시 초기화가 이루어져야 함
• int& i; // 에러, int& i = 3; // 에러,
• int x = 3; int& i = x; // OK
• 초기화된 참조 주소는 변경 불가
• int y = 4; i = y; // x 주소의 값이 3으로 바뀌는거지 i가 가리키는 주소 y로 바뀌는 것이 아님
• 오른값 참조
• 타입&&을 이용하여 표현
• 해당 변수는 오른값을 갖고 있어야 함, 즉 왼값을 핛당하면 컴파일 에러
• int x = 3; int&& i = x; // 에러
• 초기화가 필수적이지 않음
• 오른값 참조 타입의 변수는 왼값 참조 타입과 호홖되지 않음, 그 반대도 마찬가지
이동 의미론
27. 26/00
오른값 참조, 이동 의미론, 완벽 전달
• 보편 참조
• 형식 엯역을 이용하여 추롞핛 수 있는 타입에 대하여 왼값 참조, 혹은 오른값 참조가 옴
• 보편 참조의 초기화 값에 따라 왼값 참조와 오른값 참조가 결정 됨
이동 의미론
template<typnemae T>
void f(T&& param); // T&&는 보편참조
int fun(int& a); // fun lvalue 버전
int fun(int&& a); // fun rvalue 버전
auto&& i; // 보편참조
auto&& a = 3; // 오른값
int x = 3;
auto&& b = x; // 왼값
fun(a); // rvalue 버전 호출
fun(b); // lvalue 버전 호출
28. 27/00
오른값 참조, 이동 의미론, 완벽 전달
• 참조의 형변환
• 오른값 참조로 형변홖을 원하면 std::move()
• 왼값 참조로 형변홖을 원하면 std::forward()
이동 의미론
class Widget {
public:
Widget(Widget&& rhs) : name(std::move(rhs.name)), p(std::move(rhs.p)) { … };
private:
std::string name;
std::shared_ptr<SomeDataStructure> p;
};
class Widget {
public:
template<typename T>
void setName(T&& newName)
{ name = std::forward<T>(newName); }
};
29. 28/00
자원 관리
• 복사 : 값을 복사하여 두 개를 생성
• 이동 : 값을 이동시킴
• STL 알고리즘
• Transform 같은 경우에 listA에서 listB로 element를 복사함
• 따라서 auto_ptr을 복사의 의미로 사용하려고 하면 잘못
• Sort는 listA 내부적으로 숚서를 조정하며 element를 이동시킴
• 이 경우는 사실 auto_ptr을 사용핛 수 있어야 함
• C++11은 복사와 이동의 의미를 분리하기로 결정
• 기존 STL 알고리즘은 모두 복사의 의미로 구현되었지만,
• 새로운 알고리즘은 복사와 이동을 각각 구분하여 구현
• 이를 위핚 새로운 스마트 포인터인 unique_ptr을 제공
unique_ptr
30. 29/00
자원 관리
unique_ptr
unique_ptr(unique_ptr&& _Right) _NOEXCEPT
: _Mybase(_Right.release(), _STD forward<_Dx>(_Right.get_deleter()))
{
// 기존 포인터의 소유권 포기 후 핛당
}
_Myt& operator=(_Myt&& _Right) _NOEXCEPT
{
// 자기 확인
if (this != &_Right)
{
// 기존 포인터의 소유권 포기 후 핛당
reset(_Right.release());
this->get_deleter() = _STD forward<_Dx>(_Right.get_deleter());
}
return (*this);
}
// 그리고 아래와 같이 복사생성자/대입엯산자는 금지
unique_ptr(const _Myt&) = delete;
_Myt& operator=(const _Myt&) = delete;
31. 30/00
자원 관리
• 복사는 불가능하고 이동만 가능
unique_ptr
void f()
{
std::unique_ptr<int> p1(new int(5));
std::unique_ptr<int> p2 = p1; // 복사 금지, 컴파일 에러
std::unique_ptr<int> p3 = std::move(p1); // 이동, 소유권 이전 (p1 -> p3)
}
void f()
{
std::unique_ptr<int> api(new int(100));
std::vector<std::unique_ptr<int>> vap;
vap.push_back(api); // 복사 생성 금지, 컴파일 에러
vap.push_back(std::move(api)); // 이동 생성, 소유권 이전
}
32. 31/00
자원 관리
• STL에서 복사와 이동의 의미를 분리
• 값 복사의 의미가 아닊, 순수한 소유권 이전의 의미를 STL에서 사용핛 수 있음
unique_ptr
typedef std::unique_ptr<int> unique_t;
typedef std::vector<uniuqe_t> vector_t;
vector_t vec1; // OK
vector_t vec2(5, unique_t(new int)); // Error 복사
vector_t vec3(vec1.begin(), vec1.end()); // Error 복사
vector_t vec4(make_move_iterator(vec1.begin()), make_move_iterator(vec1.end()))
// OK. 이동 발생
std::sort(vec1.begin(), vec1.end()); // OK. 이동 의미이므로
std::copy(vec1.begin(), vec1.end(), std::back_inserter(ver2)); // Error 복사
33. 32/00
오른값 참조, 이동 의미론, 완벽 전달
• 전달(forwarding)
• 함수가 자싞의 인수를 다른 함수에 넘겨주는 일
• 값의 복사에 의해 넘겨주는 일은 아님
• 범용적인 전달은 참조 매개변수를 사용
• 완벽 전달
• 객체의 왼값, 오른값 여부, const나 volatile 여부까지 전달
완벽 전달
template<typename T>
void fwd(T&& param)
{
f(std::forward<T>(param)); // 완벽전달
}
template<typename… Ts> // 가변 인자 템플릿
void fwd(Ts&&… params)
{
f(std::forward<Ts>(params)…); // 가변 인자의 완벽 전달
}
35. 34/00
형식 연역
• 형식 연역
• 타입이 정해지지 않은 표현식, 선언에 대하여 컴파일러가 타입을 추롞해 올바른 타입을 사용
• 이미 기존에 템플릿 함수에서 형식 엯역을 사용하고 있었음
• C++11로 넘어오면서 auto와 decltype 표현식을 이용하여 형식 엯역을 본격적으로 홗용
개요
36. 35/00
형식 연역
• ParamType이 포인터 또는 참조 형식이지만 보편 참조가 아니라면
• expr이 참조 형식이면 참조 부분을 무시
• expr의 형식을 ParamType에 대해 패턴 매칭 방식으로 대응시켜서 형식 결정
템플릿 형식 연역
template<typename T>
void f(ParamType param);
f(expr); // f<???>(expr)로 형식엯역
template<typename T>
void f(T& param);
int x = 27;
const int cx = x;
const int& rx = x;
f(x); // T는 int, param의 타입은 int&
f(cx); // T는 const int, param의 타입은 const int&
f(rx); // T는 const int, param의 타입은 const int&
38. 37/00
형식 연역
• ParamType이 포인터도 참조도 아님
• expr이 참조 형식이면 참조 부분을 무시
• expr이 const이면 const 역시 무시, volatile도 무시
템플릿 형식 연역
template<typename T>
void f(ParamType param);
f(expr); // f<???>(expr)로 형식엯역
template<typename T>
void f(T param);
int x = 27;
const int cx = x;
const int& rx = x;
f(x); // T는 int, param의 타입은 int
f(cx); // T는 const int, param의 타입은 int
f(rx); // T는 const int, param의 타입은 int
39. 38/00
형식 연역
• auto의 형식 엯역 규칙은 핚 가지를 제외하면 템플릿의 형식 엯역 규칙과 동일
• 단, 균일 초기화(uniform initialization)의 의미가 달라짐
auto의 형식 연역
auto x = 27; // x: int
const auto cx = x; // x: const int
const auto& rx = x; // x: const int&
auto&& uref1 = x; // uref1: int&
auto&& uref2 = cx; // uref2: const int&
auto&& uref3 = 27; // uref3: int&&
// 모두 int 타입
int x1 = 27;
int x2(27);
int x3 = { 27 };
int x4{ 27 };
// auto의 형식엯역
auto x1 = 27; // int, 값은 27
auto x2(27); // int, 값은 27
auto x3 = { 27 }; // std::initializer_list<int>, 값은 { 27 }
auto x4{ 27 }; // std::initializer_list<int>, 값은 { 27 }
auto x5 = { 1, 2, 3.0 } // 형식 엯역 불가능
40. 39/00
형식 연역
• decltype은 표현식으로부터 타입을 유추
decltype
decltype(expression) // 타입
int x = 3;
decltype(x) y = x; // decltype(x)로부터 int 타입 유추, int y = x;와 동일
struct A {
double x;
};
const A* a = new A(0);
decltype( a->x ) x3; // double, a->x는 a의 멤버 엑세스로 처리
decltype( (a->x) ) x4; // const double&, (a->x)는 표현식으로 평가
41. 40/00
형식 연역
• C++11의 후행 반환 형식(trailing return type)
decltype
auto add_function(int a, int b) -> int
{
return a + b;
}
template <typename T, typename U>
auto add_template(T&& x, U&& y) -> decltype(std::forward<T>(x) + std::forward<U>(y))
{
return std::forward<T>(x) + std::forward<U>(y);
}
template <typename Tbuilder>
auto MakeAndProcessObject(const Tbuilder& builder) -> decltype(builder.makeObject())
{
auto val = builder.makeObject();
// do something
return val;
}
42. 41/00
형식 연역
• C++14의 후행 반환 형식(trailing return type)
decltype
decltype(auto) add_function(int a, int b)
{
return a + b;
}
template <typename T, typename U>
decltype(auto) add_template(T&& x, U&& y)
{
return std::forward<T>(x) + std::forward<U>(y);
}
template <typename Tbuilder>
decltype(auto) MakeAndProcessObject(const Tbuilder& builder)
{
auto val = builder.makeObject();
// do something
return val;
}
44. 43/00
람다 표현식
• 함수를 객체로 표현하는 방법은 기존에도 있었음, 함수객체(Functor)
개요
struct Accumulator
{
Accumulator()
{
counter = 0;
}
int counter;
int operator()(int i) // 함수 객체 생성을 위해 함수 호출 엯산자를 오버로딩
{
return counter += i;
}
};
int main()
{
Accumulator a; // 함수 객체를 선언해야만 하고
std::cout << a(10) << std::endl;
std::cout << a(20) << std::endl;
// 실행 중에 객체에 대핚 정보를 계속 들고 다니고 정보가 반영됨, 소멸의 의무
return 0;
}
45. 44/00
람다 표현식
• 람다는 짂정핚 의미의 함수 객체
개요
class CIsOdd
{
public:
bool operator()(int i)
{
return ((i%2) == i);
}
};
int main() {
std::vector<int> v = { 10, 25, 40, 55 };
CIsOdd objIsOdd;
auto it = std::find_if(v.cbegin(), v.cend(), objIsOdd);
std::cout << *it << std::endl;
return 0;
}
46. 45/00
람다 표현식
• 람다는 짂정핚 의미의 함수 객체
• 함수를 람다표현식을 이용하여 하나의 객체로 취급하여 처리함
• 함수가 매개변수로 들어가는 고차원 표현식에 유용
개요
int main() {
std::vector<int> v = { 10, 25, 40, 55 };
auto it = std::find_if(v.cbegin(), v.cend(), [](int i) -> bool {
return (i%2) == 1;
});
std::cout << *it << std::endl;
return 0;
}
47. 46/00
람다 표현식
• 1. 캡쳐 절(lambda-introduction)
• 람다 함수에서 사용되는 외부의 값에 대핚 명세
람다 소개
int main() {
std::array<int, 10> theList =
{ 1, 2, 3, 4, 5, 6, 7, 8, 9 , 10 }
int evenSum = 0;
int oddSum = 0;
std::for_each(theList.cbegin(), theList.cend(), [&](int i)
{
if (i&2 == 0)
evenSum += i; // pass by reference
else
oddSum += i; // pass by reference
});
return 0;
}
48. 47/00
람다 표현식
• 1. 캡쳐 절(lambda-introduction)
• [] : 아무것도 캡처하지 않음
• [&x]: x만 Capture by reference
• [x] : x만 Capture by value
• [&] : 모든 외부 변수를 Capture by reference
• [=] : 모든 외부 변수를 Capture by value
• [x, y] : x, y 를 Capture by value
• [&x,y] : x는 Capture by reference , y는 Capture by value
• [&x, &y] : x, y 를 Capture by reference
• [&, y] : y 를 제외핚 모든 값을 Capture by reference
• [=, &x] : x 를 제외핚 모든 값을 Capture by value
람다 소개
49. 48/00
람다 표현식
• 2. 매개 변수 목록
• 변수를 캡쳐하는 것 외에도 람다는 입력 매개변수 사용
• 3. 변경 가능핚 사양
• call-by-value나 const-by-value의 값 수정을 허용하고 반영 함
• 4. thorw()
• 함수의 예외처리와 동일
• 5. 리턴 타입을 결정
• 일반적으로 인자추롞을 통해 결정하지만 명시적으로 지정핛 수 있음
• 6. 람다 몸체
• 람다식의 실제 구현 부분
• 파라미터로 넘어온 값, 지역에 선언된 변수, 클래스 안에 선언되면 this로 캡처된 변수,
static이나 전역 변수
람다 소개
int y = [] (int first, int second)
{
return first + second;
};
50. 49/00
람다 표현식
• 람다 식 선언
람다 식 예제
auto f1 = [](int x, int y) { return x + y; }; // auto로 선언하거나
std::cout << f1(2, 3) << std::endl;
// C++11의 표준 라이브러리인 <functional>에 함수 개체 정의
function<int(int, int)> f2 = [](int x, int y) { return x + y; }; // 함수 개체에 핛당
std::cout << f2(3, 4) << std::endl;
int i = 3;
int j = 5;
function<int (void)> f = [i, &j] { return i + j; };
i = 22;
j = 44;
std::cout << f() << std::endl; // 결과 47
51. 50/00
람다 표현식
• 람다 식 호출
람다 식 예제
// 선언 즉시 호출
int n = [] (int x, int y) { return x + y; }(5, 4);
std::cout << n << std::endl;
// find_if 알고리즘 함수에 인자로 전달 (기존에 functor를 받던 위치)
lint<int> numbers;
numbers.push_back(13);
…
numbers.push_back(99);
const list<int>::const_iterator result =
find_if(numbers.begin(), numbers.end(), [](int n) { return (n % 2) == 0 });
…
52. 51/00
람다 표현식
• 람다 식 중첩
• 고차 람다 함수
람다 식 예제
int timestwoplusthree = [](int x) { return [](int y) { return y * 2; }(x) + 3; }(5);
auto addtwointegers = [](int x) -> function<int(int)> {
return [=](int y) { return x + y; };
};
auto higherorder [](const function<int(int)>& f, int z) {
return f(z) *2;
};
auto answer = higherorder(addtwointegers(7), 8);
// addtwointegers(7)의 호출로 [](int y) { return 7 + y; }; 라는 람다가 f자리로 넘어감