Modern C++의 타입 추론과 람다, 컨셉

Modern C++의
타입 추론과 람다, 컨셉
TP5팀 박현준
Modern C++의 방향성
• 언어적으로 Compile Time에 가능한 많은 것을 보장
• 타입추론, 상수성, 람다, 템플릿 등…
• 템플릿 메타 프로그래밍 편의성 제공
auto (C++ 11)
• 변수 정의 때 명시적으로 type을 지정하지 않아도 됨
• auto로 정의한 변수는 초기화할 때 type이 결정
• 컴파일 타임 때 type이 결정
• 템플릿 프로그래밍에 사용하면 코딩이 간편.
• 코드 가독성이 향상
auto (C++ 11)
auto x1 = 10; // x1: int
const auto *x2 = &x1; // x2: const int*
std::map<int, std::string> m;
auto i1 = m.begin();
// i1: std::map<int, std::string>::iterator
template<typename T> void f(T t);
f(expr); // expr에서 T의 타입 추론
auto v = expr; // expr에서 v의 타입 추론
decltype (C++ 11)
• decltype은 표현식으로부터 타입을 유추
decltype(expression)
• auto가 값에 상응하는 타입을 추론하는 키워드라면
decltype은 값으로부터 타입을 추출하는 키워드
decltype (C++ 11)
int x = 3;
decltype(x) y = x; // y: int
struct A { double x; };
const A* a = new A(0);
decltype(a->x) x3; // x3: double
decltype((a->x)) x4; // x4: const double&
auto 반환 (C++ 11)
• C++11부터 auto 타입 변환으로 후행 반환 형식을 제공
• decltype이 유연하게 auto 반환을 사용할 수 있음.
auto 반환 (C++ 11)
auto add_function(int a, int b) -> int {
return a+b;
}
template <typename Tbuilder>
auto MakeAndProcessObject(const Tbuilder& b)
-> decltype(builder.makeObject()) {
auto val = builder.makeObject();
return val;
}
함수 반환 값에 대한 auto(C++14)
• auto가 함수 반환 타입을 추론할 수 있도록 확장
(더 이상 후행 반환 형식을 사용할 필요 없음)
• auto 반환이 템플릿 타입 추론을 따라가기 때문에
의도하는 타입변환을 위해 decltype(auto) 형식을 사용
함수 반환 값에 대한 auto(C++14)
auto f(); // 함수 f() 선언. 반환 값 타입 불명.
auto f() { return 1; }
// f(): void -> int
auto& f(int& x) { return x*2; }
// f(): int& ->int&
…
auto i = 3; // i: int
auto r = f(i); // r: int&
함수 반환 값에 대한 auto(C++14)
decltype(auto) add_function(int a, int b) {
return a+b;
}
template <typename Tbuilder>
decltype(auto) MakeAndProcessObject(const
Tbuilder& b) {
auto val = builder.makeObject();
return val;
}
constexpr (C++ 11~)
• 변수, 함수, 클래스 등을 컴파일 타임에 결정하는 한정자
• 일반화된 상수 표현식(Generalized constant expression)
• 컴파일 시간에 연산을 가져옮으로써 런타임에 불필요한
연산 수행 시간 줄임
• constexpr을 붙이면 컴파일 시간에 ‘가능한’ 상수화 연산
을 진행 (확인은 std::is_literal_type)으로 확인
constexpr 변수 (C++ 11~)
constexpr float x = 42.f; // OK
constexpr float y (108.f); // OK
constexpr int i; // error: 초기화 필요
int j = 0;
constexpr int k = j + 1;
// error: 상수 계산이 불가능
constexpr 함수 (C++ 11~)
• constexpr을 함수 반환값에 사용
• 가상으로 재정의된 함수 X
• 함수에 constexpr을 붙일 경우 inline을 암시
• C++11에서는 함수 본문에 지역 변수를 둘 수 없고,
하나의 반환 표현식만 와야 함.
C++14에서는 제약 해제.
• 템플릿 메타 프로그래밍의 친구.
constexpr 함수 (C++ 11~)
// for C++11
constexpr int factorial(int n)
{
return n < = 1 ? 1 : (n * factorial(n-1));
}
constexpr 함수 (C++ 11~)
// for C++14
constexpr int factorial(int n)
{
int result = 0; // local variable
// multiple statements
if (n <=1) result = 1;
else result = n * factorial(n-1);
return result;
}
if constexpr (C++ 17)
• 컴파일 타임에 상수표현식의 boolean을 평가
• constexpr의 condition이 true이면 else statements가,
false이면 then statements가 컴파일에서 제외됨.
if constexpr (C++ 17)
// int*가 인자로 넘겨지면 else { return t; }가
// 버려짐, pointer가 아니면 return *t가 버려짐.
template <typename T>
auto get_value(T t)
{
if constexpr (std::is_pointer_v<T>)
return *t;
else
return t;
}
if constexpr (C++ 17)
// without if constexpr
template <int N1>
constexpr auto sum() {
return N1;
}
template <int N1, int N2, int… Ns>
constexpr auto sum() {
return N1 + sum <N2, Ns…>();
}
if constexpr (C++ 17)
// with if constexpr
template <int N, int… Ns>
constexpr auto sum() {
if constepxr (sizeof…(Ns) == 0)
return N;
else
return N + sum<Ns…>();
}
lambda (C++ 11)
• lambda 함수 또는 무명 함수라고 부름
• 함수형 프로그래밍 패러다임에서 차용,
lambda는 함수 오브젝트
• 프로그램 중간에 선언이 가능하며, 현재 프로그램의 상
태를 저장할 수 있음
• C++의 표현력을 증가 시켜 줌
• STL의 알고리즘의 활용에 유용
lambda (C++ 11)
• 1. 캡쳐 절(lambda-introduction)
[]: 캡쳐 없음
[&]: 모든 외부 변수 by ref
[=]: 모든 외부 변수 by value
• 2. 매개 변수 목록
• 3. 변경 가능 사양
• 4. 예외처리 동일
• 5. 리턴 타입을 결정
• 6. 람다 몸체
lambda (C++ 11)
// lambda를 sum에 저장하고 호출
auto sum = [] (int first, int second) {
return first + second;
};
int res = sum(1,2);
// 정의와 동시에 사용
int x = 1, y = 2;
int z = [x, y](int k){return k*(x+y);}(3);
lambda (C++ 11)
// find_if 알고리즘 함수에 인자로 전달
list<int> numbers;
numbers.push_back(1);
…
numbers.push_back(99);
auto result = //const list<int>::const_iterator
find_if(numbers.begin(), numbers.end(),
[](int n) { return (n % 2) == 0 }
); //짝수인 첫 iterator 찾음
lambda와 closure (C++ 11)
int a = 7, b = 3;
auto closureFunc = [a, b] (int x) {
cout << a*x + b << endl;
};
closureFunc(5); // 7*5+3 = 38 출력
a = 10, b = 20;
closureFunc(5);
// static lexical binding
// 70이 아니라 38 출력
generic lambda (C++ 14)
• 기존(C++11까지의) lambda 함수 인자들은 auto 키워드
를 가질 수 없었음.
• C++14부터는 auto 키워드를 사용할 수 있게 됨
generic lambda (C++ 14)
// for C++ 11
auto iAdd = [] (int a, int b) -> int
{ return a+b; }
auto fAdd = [] (float a, float b) -> float
{ return a+b; }
// for C++ 14
auto Add = [] (auto a, auto b)
/*-> decltype(a+b)*/ { return a+b; }
constexpr lambda (C++ 17)
• 람다식이 constexpr로 선언되거나 캡처되거나,
상수 내에서 각 데이터 멤버의 초기화가 허용되는 경우
상수식에 사용.
constexpr lambda (C++ 17)
int y = 32;
auto answer = [y]() constexpr {
int x = 10;
return y + x;
} // answer := 42
constexpr int Increment(int n) {
return [n] { return n + 1; }();
} // Increment(x)는 상수식
concepts (C++ 20)
• 템플릿 선언시, 템플릿으로 올 수 있는 타입에 대한
제한을 정의할 수 있음
• 기존에는 템플릿 프로그래밍에선 type_traits를 이용해서
이를 제한적으로 구현 함
• C++ 11부터 도입하려고 논의하였으나 17까지 표준에
들어오지 못함. 20에는 최우선적으로 논의 중.
concepts (C++ 20)
Defining concept
template <template-parameter-list>
concept concept-name = contraint-expression;
Using concept
template <template-parameter-list>
requires requires-swq
concepts (C++ 20)
template<typename T>
concept bool Addable = requires (T a, T b) {
a + b;
};
template<typename T> requires Addable<T>
bool add(T a, T b) { return a == b };
add(1, 2) // it’s ok, 1+2 is ok
add(“a”, “b”) // error, “a”+”b” is not ok
concepts (C++ 20)
// variable concept from the standard library
template<class T, class U>
concept bool Derived = std::is_based_of<U, T>::value;
template<class T, class U> requires Derived
T* upperCast(U* u) { return static_cast<T*>(u); }
class A {}; class B : public A {}; class C;
A* a1 = upperCast<A, B>(new B()); // it’s ok
A* a2 = upperCast<A, C>(new C()); // compiler error.
// concepts Derived doesn’t match
concepts (C++ 20)
template<typename T> using Ref = T&;
template<typename T> concept C =
requires {
typename T::inner; // required nested member name
typename S<T>; // required class template specialization
typename Ref<T>; // required alias template substitution
};
concepts (C++ 20)
template<typename T> concept C2 =
requires(T x) {
{*x} -> typename T::inner;
// the expression *x must be valid
// AND the type T::inner must be valid
// AND the result of *x must be convertible to T::inner
{x + 1} -> std::Same<int>;
// the expression x + 1 must be valid
// AND std::Same<decltype((x + 1)), int> must be satisfied
// i.e., (x + 1) must be a prvalue of type int
{x * 1} -> T;
// the expression x * 1 must be valid
// AND its result must be convertible to T
};
concepts 기타 특징 (C++ 20)
std::list<int> l = {2, 1, 3};
std::sort(l.begin(), l.end());
• 1. 컴파일 분석이 용이해짐
– 에러의 호출 위치를 내부 구현에서 컨셉으로 가져옴
– 예) 랜덤 접근 반복자가 아니라 다른 종류의 반복자를 쓸 경우
concepts 기타 특징 (C++ 20)
// Without concepts, current error display
In instantiation of 'void
std::__sort(_RandomAccessIterator,
_RandomAccessIterator, _Compare) [with
_RandomAccessIterator =
std::_List_iterator<int>; _Compare =
__gnu_cxx::__ops::_Iter_less_iter]':
error: no match for 'operator-' (operand types
are 'std::_List_iterator<int>' and
'std::_List_iterator<int>')
std::__lg(__last - __first) * 2,
concepts 기타 특징 (C++ 20)
error: cannot call function 'void
std::sort(_RAIter, _RAIter) [with _RAIter =
std::_List_iterator<int>]‘
note: concept 'RandomAccessIterator()' was not
satisfied
concepts 기타 특징 (C++ 20)
• 2. 함수 오버로드 선택
– 함수 오버로딩 시 concept에 따라 타입을 선택할 수 있음.
– 만약 둘 이상의 concept를 만족시키는 경우 좀 더 제약이 많은
콘셉트와 연관된 오버로드 선택.
concepts 기타 특징 (C++ 20)
• 3. 타입추론
– 변수 선언과 함수 변환 타입을 정할 때,
concept가 사용되어 무제한의 타입 추론을 하는 auto를 대체
auto x1 = f(y); //x1의 타입은 f의 리턴값에 의해 추론
Sortable x2 = f(y); //x2의 타입도 추론되나, Sortable을
만족하는 경우에만 컴파일 됨
1 von 40

Más contenido relacionado

Was ist angesagt?(20)

Dockerを支える技術Dockerを支える技術
Dockerを支える技術
Etsuji Nakai82.1K views
ワタシはSingletonがキライだワタシはSingletonがキライだ
ワタシはSingletonがキライだ
Tetsuya Kaneuchi17.9K views
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
Genya Murakami48.9K views
ソースコードレビューのススメソースコードレビューのススメ
ソースコードレビューのススメ
KLab Inc. / Tech474 views
샌드박스샌드박스
샌드박스
Baekjoon Choi5.2K views
System.Drawing 周りの話System.Drawing 周りの話
System.Drawing 周りの話
Satoru Fujimori939 views

Similar a Modern C++의 타입 추론과 람다, 컨셉

Changes in c++0xChanges in c++0x
Changes in c++0xSang Yeon Jeon
682 views18 Folien
강의자료 2강의자료 2
강의자료 2Young Wook Kim
1.1K views45 Folien
6 function6 function
6 function웅식 전
608 views32 Folien

Similar a Modern C++의 타입 추론과 람다, 컨셉(20)

Más de HyunJoon Park(6)

C++ Advanced 강의 5주차C++ Advanced 강의 5주차
C++ Advanced 강의 5주차
HyunJoon Park631 views
 C++ Advanced 강의 4주차 C++ Advanced 강의 4주차
C++ Advanced 강의 4주차
HyunJoon Park712 views
C++ Advanced 강의 소개C++ Advanced 강의 소개
C++ Advanced 강의 소개
HyunJoon Park536 views
C++ Advanced 강의 1주차C++ Advanced 강의 1주차
C++ Advanced 강의 1주차
HyunJoon Park680 views
C++ Advanced 강의 2주차C++ Advanced 강의 2주차
C++ Advanced 강의 2주차
HyunJoon Park413 views
C++ Advanced 강의 3주차C++ Advanced 강의 3주차
C++ Advanced 강의 3주차
HyunJoon Park450 views

Modern C++의 타입 추론과 람다, 컨셉

  • 1. Modern C++의 타입 추론과 람다, 컨셉 TP5팀 박현준
  • 2. Modern C++의 방향성 • 언어적으로 Compile Time에 가능한 많은 것을 보장 • 타입추론, 상수성, 람다, 템플릿 등… • 템플릿 메타 프로그래밍 편의성 제공
  • 3. auto (C++ 11) • 변수 정의 때 명시적으로 type을 지정하지 않아도 됨 • auto로 정의한 변수는 초기화할 때 type이 결정 • 컴파일 타임 때 type이 결정 • 템플릿 프로그래밍에 사용하면 코딩이 간편. • 코드 가독성이 향상
  • 4. auto (C++ 11) auto x1 = 10; // x1: int const auto *x2 = &x1; // x2: const int* std::map<int, std::string> m; auto i1 = m.begin(); // i1: std::map<int, std::string>::iterator template<typename T> void f(T t); f(expr); // expr에서 T의 타입 추론 auto v = expr; // expr에서 v의 타입 추론
  • 5. decltype (C++ 11) • decltype은 표현식으로부터 타입을 유추 decltype(expression) • auto가 값에 상응하는 타입을 추론하는 키워드라면 decltype은 값으로부터 타입을 추출하는 키워드
  • 6. decltype (C++ 11) int x = 3; decltype(x) y = x; // y: int struct A { double x; }; const A* a = new A(0); decltype(a->x) x3; // x3: double decltype((a->x)) x4; // x4: const double&
  • 7. auto 반환 (C++ 11) • C++11부터 auto 타입 변환으로 후행 반환 형식을 제공 • decltype이 유연하게 auto 반환을 사용할 수 있음.
  • 8. auto 반환 (C++ 11) auto add_function(int a, int b) -> int { return a+b; } template <typename Tbuilder> auto MakeAndProcessObject(const Tbuilder& b) -> decltype(builder.makeObject()) { auto val = builder.makeObject(); return val; }
  • 9. 함수 반환 값에 대한 auto(C++14) • auto가 함수 반환 타입을 추론할 수 있도록 확장 (더 이상 후행 반환 형식을 사용할 필요 없음) • auto 반환이 템플릿 타입 추론을 따라가기 때문에 의도하는 타입변환을 위해 decltype(auto) 형식을 사용
  • 10. 함수 반환 값에 대한 auto(C++14) auto f(); // 함수 f() 선언. 반환 값 타입 불명. auto f() { return 1; } // f(): void -> int auto& f(int& x) { return x*2; } // f(): int& ->int& … auto i = 3; // i: int auto r = f(i); // r: int&
  • 11. 함수 반환 값에 대한 auto(C++14) decltype(auto) add_function(int a, int b) { return a+b; } template <typename Tbuilder> decltype(auto) MakeAndProcessObject(const Tbuilder& b) { auto val = builder.makeObject(); return val; }
  • 12. constexpr (C++ 11~) • 변수, 함수, 클래스 등을 컴파일 타임에 결정하는 한정자 • 일반화된 상수 표현식(Generalized constant expression) • 컴파일 시간에 연산을 가져옮으로써 런타임에 불필요한 연산 수행 시간 줄임 • constexpr을 붙이면 컴파일 시간에 ‘가능한’ 상수화 연산 을 진행 (확인은 std::is_literal_type)으로 확인
  • 13. constexpr 변수 (C++ 11~) constexpr float x = 42.f; // OK constexpr float y (108.f); // OK constexpr int i; // error: 초기화 필요 int j = 0; constexpr int k = j + 1; // error: 상수 계산이 불가능
  • 14. constexpr 함수 (C++ 11~) • constexpr을 함수 반환값에 사용 • 가상으로 재정의된 함수 X • 함수에 constexpr을 붙일 경우 inline을 암시 • C++11에서는 함수 본문에 지역 변수를 둘 수 없고, 하나의 반환 표현식만 와야 함. C++14에서는 제약 해제. • 템플릿 메타 프로그래밍의 친구.
  • 15. constexpr 함수 (C++ 11~) // for C++11 constexpr int factorial(int n) { return n < = 1 ? 1 : (n * factorial(n-1)); }
  • 16. constexpr 함수 (C++ 11~) // for C++14 constexpr int factorial(int n) { int result = 0; // local variable // multiple statements if (n <=1) result = 1; else result = n * factorial(n-1); return result; }
  • 17. if constexpr (C++ 17) • 컴파일 타임에 상수표현식의 boolean을 평가 • constexpr의 condition이 true이면 else statements가, false이면 then statements가 컴파일에서 제외됨.
  • 18. if constexpr (C++ 17) // int*가 인자로 넘겨지면 else { return t; }가 // 버려짐, pointer가 아니면 return *t가 버려짐. template <typename T> auto get_value(T t) { if constexpr (std::is_pointer_v<T>) return *t; else return t; }
  • 19. if constexpr (C++ 17) // without if constexpr template <int N1> constexpr auto sum() { return N1; } template <int N1, int N2, int… Ns> constexpr auto sum() { return N1 + sum <N2, Ns…>(); }
  • 20. if constexpr (C++ 17) // with if constexpr template <int N, int… Ns> constexpr auto sum() { if constepxr (sizeof…(Ns) == 0) return N; else return N + sum<Ns…>(); }
  • 21. lambda (C++ 11) • lambda 함수 또는 무명 함수라고 부름 • 함수형 프로그래밍 패러다임에서 차용, lambda는 함수 오브젝트 • 프로그램 중간에 선언이 가능하며, 현재 프로그램의 상 태를 저장할 수 있음 • C++의 표현력을 증가 시켜 줌 • STL의 알고리즘의 활용에 유용
  • 22. lambda (C++ 11) • 1. 캡쳐 절(lambda-introduction) []: 캡쳐 없음 [&]: 모든 외부 변수 by ref [=]: 모든 외부 변수 by value • 2. 매개 변수 목록 • 3. 변경 가능 사양 • 4. 예외처리 동일 • 5. 리턴 타입을 결정 • 6. 람다 몸체
  • 23. lambda (C++ 11) // lambda를 sum에 저장하고 호출 auto sum = [] (int first, int second) { return first + second; }; int res = sum(1,2); // 정의와 동시에 사용 int x = 1, y = 2; int z = [x, y](int k){return k*(x+y);}(3);
  • 24. lambda (C++ 11) // find_if 알고리즘 함수에 인자로 전달 list<int> numbers; numbers.push_back(1); … numbers.push_back(99); auto result = //const list<int>::const_iterator find_if(numbers.begin(), numbers.end(), [](int n) { return (n % 2) == 0 } ); //짝수인 첫 iterator 찾음
  • 25. lambda와 closure (C++ 11) int a = 7, b = 3; auto closureFunc = [a, b] (int x) { cout << a*x + b << endl; }; closureFunc(5); // 7*5+3 = 38 출력 a = 10, b = 20; closureFunc(5); // static lexical binding // 70이 아니라 38 출력
  • 26. generic lambda (C++ 14) • 기존(C++11까지의) lambda 함수 인자들은 auto 키워드 를 가질 수 없었음. • C++14부터는 auto 키워드를 사용할 수 있게 됨
  • 27. generic lambda (C++ 14) // for C++ 11 auto iAdd = [] (int a, int b) -> int { return a+b; } auto fAdd = [] (float a, float b) -> float { return a+b; } // for C++ 14 auto Add = [] (auto a, auto b) /*-> decltype(a+b)*/ { return a+b; }
  • 28. constexpr lambda (C++ 17) • 람다식이 constexpr로 선언되거나 캡처되거나, 상수 내에서 각 데이터 멤버의 초기화가 허용되는 경우 상수식에 사용.
  • 29. constexpr lambda (C++ 17) int y = 32; auto answer = [y]() constexpr { int x = 10; return y + x; } // answer := 42 constexpr int Increment(int n) { return [n] { return n + 1; }(); } // Increment(x)는 상수식
  • 30. concepts (C++ 20) • 템플릿 선언시, 템플릿으로 올 수 있는 타입에 대한 제한을 정의할 수 있음 • 기존에는 템플릿 프로그래밍에선 type_traits를 이용해서 이를 제한적으로 구현 함 • C++ 11부터 도입하려고 논의하였으나 17까지 표준에 들어오지 못함. 20에는 최우선적으로 논의 중.
  • 31. concepts (C++ 20) Defining concept template <template-parameter-list> concept concept-name = contraint-expression; Using concept template <template-parameter-list> requires requires-swq
  • 32. concepts (C++ 20) template<typename T> concept bool Addable = requires (T a, T b) { a + b; }; template<typename T> requires Addable<T> bool add(T a, T b) { return a == b }; add(1, 2) // it’s ok, 1+2 is ok add(“a”, “b”) // error, “a”+”b” is not ok
  • 33. concepts (C++ 20) // variable concept from the standard library template<class T, class U> concept bool Derived = std::is_based_of<U, T>::value; template<class T, class U> requires Derived T* upperCast(U* u) { return static_cast<T*>(u); } class A {}; class B : public A {}; class C; A* a1 = upperCast<A, B>(new B()); // it’s ok A* a2 = upperCast<A, C>(new C()); // compiler error. // concepts Derived doesn’t match
  • 34. concepts (C++ 20) template<typename T> using Ref = T&; template<typename T> concept C = requires { typename T::inner; // required nested member name typename S<T>; // required class template specialization typename Ref<T>; // required alias template substitution };
  • 35. concepts (C++ 20) template<typename T> concept C2 = requires(T x) { {*x} -> typename T::inner; // the expression *x must be valid // AND the type T::inner must be valid // AND the result of *x must be convertible to T::inner {x + 1} -> std::Same<int>; // the expression x + 1 must be valid // AND std::Same<decltype((x + 1)), int> must be satisfied // i.e., (x + 1) must be a prvalue of type int {x * 1} -> T; // the expression x * 1 must be valid // AND its result must be convertible to T };
  • 36. concepts 기타 특징 (C++ 20) std::list<int> l = {2, 1, 3}; std::sort(l.begin(), l.end()); • 1. 컴파일 분석이 용이해짐 – 에러의 호출 위치를 내부 구현에서 컨셉으로 가져옴 – 예) 랜덤 접근 반복자가 아니라 다른 종류의 반복자를 쓸 경우
  • 37. concepts 기타 특징 (C++ 20) // Without concepts, current error display In instantiation of 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = std::_List_iterator<int>; _Compare = __gnu_cxx::__ops::_Iter_less_iter]': error: no match for 'operator-' (operand types are 'std::_List_iterator<int>' and 'std::_List_iterator<int>') std::__lg(__last - __first) * 2,
  • 38. concepts 기타 특징 (C++ 20) error: cannot call function 'void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]‘ note: concept 'RandomAccessIterator()' was not satisfied
  • 39. concepts 기타 특징 (C++ 20) • 2. 함수 오버로드 선택 – 함수 오버로딩 시 concept에 따라 타입을 선택할 수 있음. – 만약 둘 이상의 concept를 만족시키는 경우 좀 더 제약이 많은 콘셉트와 연관된 오버로드 선택.
  • 40. concepts 기타 특징 (C++ 20) • 3. 타입추론 – 변수 선언과 함수 변환 타입을 정할 때, concept가 사용되어 무제한의 타입 추론을 하는 auto를 대체 auto x1 = f(y); //x1의 타입은 f의 리턴값에 의해 추론 Sortable x2 = f(y); //x2의 타입도 추론되나, Sortable을 만족하는 경우에만 컴파일 됨