C++/기타

[C++17] if constexpr

sseram 2023. 5. 17. 10:27
반응형

https://en.cppreference.com/w/cpp/language/if

 

if statement - cppreference.com

Conditionally executes another statement. Used where code needs to be executed based on a run-time or compile-time (since C++17) condition, or whether the if statement is evaluated in a manifestly constant-evaluated context (since C++23). [edit] Syntax att

en.cppreference.com

 

 

 

C++17 부터 추가된 기능으로, 실행 전 빌드 할 때에 해당 구문을 평가하여 조건에 맞으면 빌드하고, 맞지 않으면 아예 빌드하지 않아 없는 코드 처리해버린다.

-> 상수 값들이면, 컴파일 시간 때에 미리 조건을 확인하고 빌드 할 지 안 할지를 결정할 수 있게 된다.

 

 

원래는 enable_if 로 여러 개의 함수를 만들고, 해당 함수에서 사용되는 type에 따라 하나하나 만들어 주어야 했지만 이 if constexpr 덕분에 그런 번거로움을 줄일 수 있다.

 


 

enum class closeOpen{ close = 0, open};

int main() {
	auto arglist = make_tuple(3, 2.2, closeOpen::open, string("tada"));

	CheckArgType(get<0>(arglist));
	CheckArgType(get<1>(arglist));
	CheckArgType(get<2>(arglist));
	CheckArgType(get<3>(arglist));

	
	/* std::apply([&](auto... args) {
		(CheckArgType(args), ...);
		}, arglist); */


	return 0;
}

 

 

 

이런 식으로 다양한 type의 arg를 가진 tuple이 있고, checkArgType이라는 함수를 통해 각각이 어떠한 타입인지 체크하여 유저에게 보여 줄 예정이다. 

 

그리고 그 결과는 아래와 같이 나오게 할 것이다.

 

 

 

 

 

 

먼저 C++11 부터 사용 가능했던 enable_if를 사용하여 짜면 아래와 같이 나오게 된다.

 

template <typename T, typename enable_if_t<is_enum_v<T>, bool> = true >
void CheckArgType(T arg) {
	cout << "[enum type] " << static_cast<int>(arg) << endl;
}

template <typename T, typename enable_if_t<is_same_v<string, T>, bool> = true >
void CheckArgType(T arg) {
	cout << "[string] [" << arg << "] length : " << arg.length() << endl;
}


template <typename T, typename enable_if_t<is_integral_v<T>, bool> = true>
void CheckArgType(T arg) {
	cout << "[int] " << arg << endl;
}

template <typename T, typename enable_if_t<is_same_v<double, T>, bool> = true>
void CheckArgType(T arg) {
	cout << "[double] " << arg << endl;
}

 

이렇게 특정 타입일 때에만 아래 함수로 들어가게 하면 구현이 가능하다.

다만 보다싶이 하나의 함수인데 여러 군데에 다시 재정의를 해야 하는 일이 좀 귀찮아진다. 그렇다고 하나의 함수 정의 안에서 처리하기엔

 

이런 식으로 수많은 에러를 마주하게 된다.

 

 

더군다나, 12번째 줄을 보면 arg.length()를 구하는 함수가 있다. 만약 arg가 string type이거나, length()라는 메소드를 가지고 있으면 다행이지만, int 같은 애들이 넘어오면 어떻게 될까?

int a = 3; a.lenght()??

 

 

 

위와 같은 문제를 if constexpr로 해결이 가능하다.


template <typename T>
void CheckArgType(T arg) {
	if constexpr (is_enum_v<T>) {
		cout << "[enum type] " << static_cast<int>(arg) << endl;
	}
	else if constexpr (is_same_v<string, T>) {
		cout << "[string] [" << arg << "] length : " << arg.length() << endl;
	}
	else if constexpr (is_integral_v<T>) {
		cout << "[int] " << arg  << endl;
	}
	else if constexpr (is_floating_point_v<T>) {
		cout << "[floating] " << arg << endl;
	}
	else {
		cout << "what is it?" << endl;
	}
}

 

함수 하나 안에서 한 눈에 보기 쉽게 정의 가능하다. constexpr 한정자를 붙임으로써 내가 필요 없을 때에는 빌드하지 않는다.

 

 

	auto arglist = make_tuple(3, 2.2, closeOpen::open, string("tada"));

	CheckArgType(get<0>(arglist));

해당 라인을 수행할 때에는

이 것들만 빌드가 되고,

 

 

 

	auto arglist = make_tuple(3, 2.2, closeOpen::open, string("tada"));

	CheckArgType(get<3>(arglist));

해당 라인을 수행할 때에는

이것들만 빌드가 되게 된다.

 

 

 

이런 식으로 조건문 내부의 값을 알 수 있다면, 컴파일 타임에 미리 해당 조건을 확인하여 어느 부분만 빌드할지를 결정할 수 있게 된다.

 

 

 

 

반응형

'C++ > 기타' 카테고리의 다른 글

[C++] 함수에 const 한정자  (0) 2023.06.15
[C++] type cast (static_cast, dynamic_cast, const_cast, reinterpret_cast)  (0) 2023.05.18
[C++] LValue vs RValue (3)  (1) 2023.05.15
[C++] LValue vs RValue (2)  (1) 2023.05.10
[C++] LValue vs RValue (1)  (0) 2023.04.29