1. 함수 삭제(delete function)
- C++ 11부터 추가된 문법
- 아래 코드의 의미 : int를 인자로 받는 move 함수는 삭제하겠다.
- 삭제된 함수를 호출하면 컴파일 시간에 오류가 발생한다.
void move(int) = delete; // 함수 삭제
int main() {
move(10); // 컴파일 에러
}
1.1 함수를 제공하지 않는 것 vs 함수를 삭제 하는 것
- 함수를 제공하지 않을 경우
=> 함수 호출 시 인자의 암시적 형 변환을 통해서 호출 가능한 함수를 찾게 된다.
=> 데이터 손실이 있을 수 있어 손해
=> 해결 방법은 double 타입의 함수를 만들어 대응
=> 함수를 선언만 제공한다면 함수 호출 시 링크 에러(link error) 발생
- 함수를 삭제(delete) 할 경우
=> 함수 호출 시 컴파일 에러 발생
결론 : 함수를 제공하지 않는다고 오류가 나지 않고, 암시적 형 변환으로 데이터 손실이 있을 수 있다. 함수를 삭제할 경우 컴파일 에러가 나므로 확실히 알 수 있다.
int gcd(int a, int b) {
return b != 0 ? gcd(b, a%b) : a;
}
int main() {
gcd(2, 10); // ok
gcd(1.2, 4.8); // gcd(double, double)?
}
- 암시적 변환에 의한 의도 하지 않은 함수가 호출되는 것을 막기 위해
- 템플릿이 특정 타입의 함수를 생성하지 못하게 하기 위해
- 컴파일러가 자동으로 생성하는 멤버함수를 사용하지 못하게(생성하지 못하게) 하기 위해 -> 가장 널리 사용
template<typename T>
T square(T a) {
return a * b;
}
char square(char) = delete
int main() {
square(3); // square(int, int)
square(3.3); // square(double, double)
square('a'); // square(char, char) => 함수 삭제를 할 경우 컴파일 에러 발생
}
2. trailing return type (후위 반환 타입)
2.1 함수의 후위 반환 타입 표기법
//int square(int a)
auto square(int a) -> int {
return a * a;
}
//int main()
auto main() -> int {
square(3);
}
- 함수를 만들 때 사용하는 새로운 표기법
=> 함수의 이름 앞에는 auto를 적고, 괄호 뒤쪽에 -> 반환 타입을 적는 표기법
- trailing return type 또는 suffix return type
- C++11 부터 지원
- 람다 표현식이나 함수 템플릿을 만들 때 주로 사용
2.2 후위 반환 타입 표기법이 필요한 경우
template<typename T1, typename T2>
? add(T1 a, T2 b) {
return a + b;
}
int main() {
add(1, 2.3);
}
- 위와 같은 경우에는 ?를 어떻게 적어야 할까?
- 방법1. decltype(a + b) add(T1 a, T2 b) ?
=> 변수 a와 b가 선언되지 않아 쓸 수 없다. 선언되는 시점은 T1 a지만 사용될 때 a는 선언되지 않은 상태
- 방법2. auto add(T1 a, T2 b) -> decltype(a + b) ?
=> 컴파일 오류 없음. C++11부터 가능
=> C++14부터는 -> decltype(a+b)를 지워도 됨. // return에 따라 반환 타입이 결정 됨.
3. constexpr function
constexpr int add(int a, int b) {
return a + b;
}
int main() {
add(1, 2);
}
3.1 constexpr 키워드
- 컴파일 시간의 의미를 가지는 키워드 - C++11
- 활용1. constexpr 상수 => constexpr int c = 10;
- 활용2. constexpr function
- 활용3. if constexpr => if constexpr(c==10) -> 추후 다룰 예정
template<typename T, int N>
struct Buffer {
T data[N];
}
constexpr int add(int a, int b) {
return a + b;
}
int main() {
int x = 1;
int y = 1;
int n1 = add(1, 1);
int n2 = add(x, y);
Buffer<int, 1024> b1; // ok
Buffer<int, x> b2; // error
Buffer<int, add(1, 2)> b2; // ok
Buffer<int, add(x, 2)> b2; // error
}
3.2 constexpr function의 의미
- 함수의 인자 값을 컴파일 시간에 결정할 수 있으면 컴파일 시간에 함수를 실행
- 함수의 인자 값을 컴파일 시간에 결정할 수 없으면 실행시간에 함수를 실행
3.3 template parameter
- 템플릿 인자로 타입 뿐 아니라 정수형 상수도 사용할 수 있다.
- 모든 템플릿 인자는 컴파일 시간에 결정되어야 한다.
#include <iostream>
constexpr int factorial(int n) {
//
//
//
if(n==1)
return 1;
return n * factorial(n-1);
}
int main() {
int n = factorial(5);
std::cout << n << std::endl;
}
3.4 constexpr function의 제약
- factorial 함수 내의 주석처리 된 3줄 부분에 파일을 열 수 있을까? 실행할 때 열어야 할텐데
- 또, 동적 메모리 할당을 할 수 있을까?
- C++11에서는 constexpr 함수가 컴파일 시간에 수행되기 위한 제약 조건을 많이 가지고 있었다.
=> return 문장이 한번만 나와야 한다.
- C++14에서는 대부분 제약이 사라지고 일부 조건만 남아있다.
=> 파일을 오픈 하거나, 동적으로 메모리를 할당 할 수 없다.
=> 가상함수가 될 수 없다.
=> cppreference.com 참고
4. lambda expression (람다 표현식)
#include <iostream>
void num(int a) {
std::cout << "num : " << a << std::endl;
}
int main() {
num(1); // 함수(함수 인자) - 함수 호출
// 람다 표현식
[](int a) {
std::cout << "num : " << a << std::endl;
}(10);
}
4.1 람다 표현식의 개념
- 1. 일반적인 함수
=> global space에 만들어 놓고 필요할 때 함수의 이름을 사용해서 호출한다.
- 2. 람다 표현식(lambda expression)
=> 코드 안에서 이름이 없는 함수를 만들어서 사용하는 것
=> 익명의 함수(anonymouse function) , 함수 리터럴(literal)
=> 함수 반환타입과 이름을 제거 하고 [ ]를 표기 한다.
#include <iostream>
int add(int a, int b) { return a + b; }
int main() {
int n1 = add(1, 2);
// 람다표현식 생성, 함수를 만듬, 사용은 안한 상태
[](int a, int b) { return a + b; };
// 람다표현식으로 생성한 함수를 호출
int n2 = [](int a, int b) { return a + b; }(1, 2);
}
4.2 람다 표현식의 모양
- 일반 함수의 모양에서 반환타입과 함수 이름을 제거하고 []를 표기 한다.
- [] => lambda introducer , 람다 표현식이 시작됨을 나타낸다.
#include <iostream>
#include <algorithm>
bool cmp(int a, int b) { return a > b; }
int main() {
int x[10] = {1, 5, 2, 6, 9, 7, 3, 8, 10, 4};
std::sort(x, x+10); // 배열의 요소 소팅(시작, 마지막 요소의 다음 주소)
// std::sort(x, x+10, 크기 비교함수); 를 이용해서 큰 수부터 나열로 바꿀 수 있다.
std::sort(x, x+10, cmp); // 10부터 내림차순으로 정렬
std::sort(x, x+10,
[](int a, int b) {return a > b; }); // 위와 같은 문법
for(auto n : x) // 범위 지정법
std::cout << n << ", ";
}
4.3 람다 표현식의 활용
- sort 함수
=> 배열의 시작 주소와 마지막 다음 주소를 받아서 요소를 퀵소트 알고리즘으로 정렬하는 C++ 표준 함수
=> 3번째 인자로 함수를 전달하면 요소의 비교정책을 변경할 수 있다.
=> <algorithm> 헤더가 필요 하다.
- 함수가 필요한 곳에 함수 이름 대신 람다 표현식을 사용할 수 있다.
- 위의 코드에서 cmp함수와 같이 한 번쓰고 말 함수 같은 경우 밖에 선언하기 보다 안에서 한 번 쓰고 말자.
'프로그래밍 > C++' 카테고리의 다른 글
[C++] 레퍼런스(reference) (0) | 2019.10.22 |
---|---|
[C++] range for / if init / if constexpr (0) | 2019.10.18 |
[C++] C언어와 다른 C++ 함수(1) (0) | 2019.10.09 |
[C++] 변수(2) (0) | 2019.10.05 |
[C++] 변수(1) (0) | 2019.10.05 |