(코딩 규칙) constexpr 함수

보물창고·2022년 8월 11일
0

c++ basic 코드누리

목록 보기
15/50

코딩 규칙 240820

: 함수 내에서 다른 constexpr 함수를 반환하지 않을 경우, constexpr 붙이자.
컴파일에 처리하든, 런타임에 처리하든 알아서 처리하는 구조로 함수를 만들자.

  • constexpr 함수에서 constexpr 이 아닌 함수 호출시 에러 발생한다.
    -> 출처 씹어먹는 c++

다른 예시

  • 아래 두개의 코드 차이를 알아야 한다.

1) constexpr & 반환의 경우.
: 지금의 경우, 반환하는 것이 lvalue 이기 때문에 상수 처리되지 않는다.

  • 템플릿 안들어가지는 것을 확인함.

2) 이 때는 반드시 상수로 처리하는 것이기 때문에 외부에서 set하고 있어서 에러 발생이다.

3) 번외
: 이렇게 하게 되면, func 함수는 상수식이기 때문에 템플릿 인자로 보낼 수 있다.

constexpr 생성자.

: 객체로 constexpr 을 설정할 수 있다.

특징
: c++ 핵심 가이드라인에 작성됨
1) 가상 함수 사용 못한다.
2) 가상 상속 못한다.
3) 반드시 생성자를 두어야 하고, 생성자의 인자는 모두 리터럴이어야 한다.

예시 코드

  • 출처 : 씹어먹는 c++

  • constexpr 객체는 가상함수와 const 함수는 호출이 안된다.

  • 신기하게도 constexpr을 지우면, func 함수와 SetX 함수는 호출이 되지만,
    이제는 상수가 아니기 때문에 template에 인자로 전달 못한다.


#include <vector>
#include <algorithm>
#include <map>
#include <string>

#include <iostream>
#include <queue>
using namespace std;


#include <iostream>

class Vector {
public:
	constexpr Vector(int x, int y) : x_(x), y_(y) {}

	constexpr int x() const { return x_; }
	constexpr int y() const { return y_; }

	virtual void func() {};
	void SetX(int _x) { x_ = _x; }
private:
	int x_;
	int y_;
};

constexpr Vector AddVec(const Vector& v1, const Vector& v2) {
	return { v1.x() + v2.x(), v1.y() + v2.y() };
}

template <int N>
struct A {
	int operator()() { return N; }
};

int main() {
	constexpr Vector v1{ 1, 2 };
	constexpr Vector v2{ 2, 3 };
	
	// constexpr 객체의 constexpr 멤버 함수는 역시 constexpr!
	A<v1.x()> a;
	std::cout << a() << std::endl;

	// AddVec 역시 constexpr 을 리턴한다.
	A<AddVec(v1, v2).x()> b;
	std::cout << b() << std::endl;
}

공부 필요. : 240729

: constexpr 키워드 자체가 상수성을 부여하는 걸까?
-> 반드시 상수성이 주어지는 것은 아니다.

중요하게 봐야할점

: constexpr 함수는 상수인가에 대해서

  • -> constexpr 함수는 반드시 상수가 아니고, 인자가 리터럴 상수일 때, 컴파일 타임에 실행하고 , 변수 일 경우에는 런타임에 처리한다.

  • 확인할 수 있는 예시 코드
    : 씹어먹는 c++ 참고
    -> 즉 리터럴 값이 인자로 들어온다면 반환값이 상수로 처리된다는 것이다.

-> 변수를 넣으면 컴파일 처리되지 않으므로 템플릿에서 오류 발생한다.
-> 즉 이때는 반환값이 상수로 처리되지 않았다는 것을 의미하게 된다.

참고 자료

: 모던 이펙티브 c++ 항목 15

constexpr 변수 사용.

: 컴파일 시간의 의미를 가짐.
-> 컴파일 시간에 처리되는 상수

활용하는 곳

  1. constexpr 함수
  2. constexpr 상수.
  3. if constexpr : 새로운 제어문

constexpr 함수 개념과 핵심.

함수의 인자 값을 컴파일 시간에 결정할 수 있으면 "컴파일 시간에 함수를 실행함." 그리고 이때는 상수 타입으로 반환된다.
그렇지 않다면, "실행 시간에 함수를 실행함."

  • 위의 내용에 의해 problem코드에서 int n = add(1,1) 를 호출한다면, 인자인 1과 1 이 상수이기 때문에 컴파일 시간에 함수를 실행함.
  • 하지만 problem 코드를 인용해 int n = add(aa , 5) 일 경우는 , aa는 변수이기 때문에 실행시간에 함수를 실행함.

1) 컴파일시간에 실행 할때는 리터럴 상수가 인자로 들어올 때
2) 런타입 시간에 실행 할때는 변수가 인자로 들어올 때

실행시간에 호출되는지? 컴파일 시간에 호출되는지??

  • template 파라미터의 특성을 이용해 실행시간에 처리되는지?
    컴파일 시간에 함수 실행되는지 알아보자.
  • template 파라미터의 특징.
  1. 템플릿 인자로 타입뿐 아니라 "정수형 상수"도 사용할 수 있음.
  2. 모든 템플릿 인자는 "컴파일 시간에 결정"되어야 함.
  • constexpr의 개념을 확인하기 위한 예제 코드
    -> 즉, 리터럴 값이 인자로 들어오게 되면, 반환값은 상수다!
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;
    
    Buffer<int, 1024> b1;
    Buffer<int ,x > b2; // error : x는 실행할때 알기 때문.
    Buffer<int, add(1, 2)> b3;
    Buffer<int ,add(x, 2)> b4; // error : add(x, 2)는 문제없지만, 실행할때 호출되는 것이므로, 오류 발생함.
}

-> error가 발생한 이유
: add(x, 2) 에서 x는 변수이므로, 이 때는 런타임에 add가 처리됨.
--> template은 컴파일 시간에 처리되어야 하기 때문에 에러 발생함.

제약

  1. 컴파일 시간에 함수를 실행하기 때문에, 함수 내부에서 동적할당, 파일 오픈
    등의 동작을 할 수 없음.
  2. 가삼함수가 될수 없음.
  3. constexpr 함수 내에서 일반 함수 호출 불가함.

problem

가) consterpr로 함수를 만들어보고,
리터럴 상수를 인자로 넣어서 call 하자.

나) 변수를 인자로 넣어서 call 하자.
: add(aa, 5)는 실행시간에 실행됨.
: add(1,4)는 컴파일 시간에 실행됨.
-> 즉 리터럴값도 들어갈수 있고, 변수도 들어갈 수 있다!

라) constexpr의 타입이름을 출력해보자.
template은 struct 형식으로, struct내의 배열 변수의 크기를 결정하는
내용으로 만들어보아라.

  • 힌트

  • 결과
    -> constexpr에 변수가 들어갔기 때문에, 런타임에 실행
    --> 템플릿의 경우, 컴파일 시간에 타입이 정해져야 하는데...
    N값에 변수가 들어가므로, 당연히 빌드 오류가 발생됨을 확인할 수 있음.

  • 리터럴값인 경우, 컴파일 상수로 반환되면서 템플릿인자로 사용할 수 있게 되었다.

마) constexpr은 상수인지를 확인하기 위해서 ,
레퍼런스 타입으로 함수를 만들고, 외부에서
값 대입을 해보아라..

1) 일단을 실험을 위해서 return a + b; 가 아니라 return a; 로 변경하라. 인자로 참조 타입으로 받아라.

-> 4에서 17로 변경됨을 확인함.

2) const 함수로 만들어서 확인하라 .

  • -> const 속성에 의해서 상수이기 때문에 아무리 레퍼런스반환이라고 하더라도 외부에서의 대입을 막고 있는 것을 확인할 수 있다.

    -> 역시 안됨.

3) constexpr로 만들어서 확인하라.
-> 상수가 아님을 확인할 수 있음.
-> a가 리터럴이 아니기 때문에 상수타입으로 결정되지 않는다!

-> 변수가 들어가서 런타임에 실행되어서 상수 를 반환한 것이 아니다.
어쨋든 상수 함수라고는 할 수 없는 상태임.
--> 일반함수로 동작함.

4) 한번 더 확인하는 예시코드

  • constexpr 변수를 통해 add 함수가 상수로 처리되는지 아닌지를 확인함.
  • 39번줄은 상수가 아닌 값이 나와서 오류 발생
  • 40번 줄은 상수가 나와서 문제 없음.

5) 추가
: 타입을 확인해보자.

  • constexpr 은 상수가 아닌가?
    : 인자에 따라서 상수성을 지닐수 있고, 아닐 수 있다.
    -> 지금의 경우는 그거 부스트 해서 제대로 확인해야 한다. ..

  • const 함수는 상수성이 있다.

결론

: constexpr 함수는 컴파일 시간에 처리가 가능하면 ,
컴파일 시간에 함수를 실행해버림.

profile
🔥🔥🔥

0개의 댓글