2023.05.23 - [C++/STL] - [C++20] Concepts
[C++20] Concepts
https://en.cppreference.com/w/cpp/concepts Concepts library (since C++20) - cppreference.com The concepts library provides definitions of fundamental library concepts that can be used to perform compile-time validation of template arguments and perform fun
donot-simsim.tistory.com
위 글에서 한번 다루긴 했는데, 그때는 너무 수박 겉핥기식으로 해둬서...
조금 더 공부했기에 다시 올려본다.
C++ 20 이전에는 if constexpr, 부분 특수화 template 을 이용해 여러 가지 type에 대한 template를 나눴다면,
C++ 20부터는 concept과 requires를 이용하여 좀 더 간단하고 직관적이게 나눌 수 있게 되었다.
Concept
== named set of requirements
타입이 가져야 할 요구 조건들의 집합.
그리고 그 요구 조건들의 집합을 코드로 작성.
기본 형태는 아래와 같다.
template <typename T>
concept concept_name = constraint expression;
concept_name에는 변수같이 이름을 넣으면 되고, 뒤 constraint expression 에 여러 조건을 넣어 사용 할 수 있다.
다만 여기서 말하는 조건들은 [컴파일 시 조사] 가 가능하여야 하고, 반드시 [bool type] 이어야 한다.
위에서 말한 조건을 만족하는 concept을
template <typename T>
concept C1 = true;
constexpr bool yes() {return true;}
template <typename T>
concept C2 = yes();
template <typename T>
concept C3 = sizeof(T) > 4;
template <typename T>
concept C4 = std::is_integral_v<T>;
template <typename T>
concept C5 = C1<T> || C2<T>;
template <typename T>
concept C6 = requires(T& c)
{
c.begin();
};
위처럼.
그리고 concept에 바로 type을 집어넣어, 해당 type이 concept에 맞는지 조사할 수 있다.
int main() {
std::cout << C1<double> << std::endl; // true
std::cout << C2<double> << std::endl; // true
std::cout << C3<double> << std::endl; // true
std::cout << C4<double> << std::endl; // false
std::cout << C5<double> << std::endl; // true
std::cout << C6<double> << std::endl; // false
}
위 concept를 사용하여 함수를 하나 만들어 보자.
pointer가 와도, 일반 변수가 와도 print 를 할 수 있는 function을 만들 것이다.
#include <iostream>
template <typename T>
void pointer_print(T a) {
// TODO
};
int main() {
int a = 3;
pointer_print(&a);
pointer_print(a);
}
각각의 C++ 버전 concept에 따라 구현을 해 보자
C++14
#include <iostream>
template <typename T,
typename std::enable_if_t<!std::is_pointer_v<T>, bool> = true>
void pointer_print(T a) {
std::cout << a << std::endl;
}
template <typename T,
typename std::enable_if_t<std::is_pointer_v<T>, bool> = true>
void pointer_print(T a) {
std::cout << *a << std::endl;
};
int main() {
int a = 3;
pointer_print(&a);
pointer_print(a);
}
C++ 17
#include <iostream>
template <typename T>
void pointer_print(T a) {
if constexpr (std::is_pointer_v<T>) {
std::cout << *a << std::endl;
}
else {
std::cout << a << std::endl;
}
};
int main() {
int a = 3;
pointer_print(&a);
pointer_print(a);
}
C++ 20
#include <iostream>
#include <concepts>
template<typename T>
concept pointer_container = std::is_pointer_v<T>;
template <typename T>
void pointer_print(T a) {
std::cout << a << std::endl;
};
template <typename T>
requires pointer_container<T>
void pointer_print(T a) {
std::cout << *a << std::endl;
};
int main() {
int a = 3;
pointer_print(&a);
pointer_print(a);
}
이렇게만 보면
잉? if constexpr 쓰는게 가장 편하게 쓸 수 있지 않나? 라고 생각한다.
하지만 concept의 진가는 requires와 함께, 좀 더 복잡한 확인이 들어갈 떄 발휘한다.
requires는 다음 글에서..
* 잘못된 정보는 덧글로 알려주시면 감사한 마음으로 수정하겠습니다.
'C++ > STL' 카테고리의 다른 글
[C++20] <=> 삼항 연산자(우주선 연산자) (1) | 2023.12.03 |
---|---|
[C++ 11] std::initializer_list (2) | 2023.11.19 |
[C++17] std::variant (1) | 2023.11.12 |
[C++] remove(remove_if) vs erase(erase_if) (0) | 2023.07.11 |
[C++20] Span (1) | 2023.07.04 |