C++ 20 : Concept(중요)

RuuNee
|2024. 5. 14. 02:53
반응형

 

우리가 C#에서 제네릭 문법을 사용할 때 위와 같은 코드로 추가적인 조건을 붙여줄 수 있었다.

기존 C++에는 비슷하게 나마 사용하려면 enable_if를 사용하여 복잡하게 코드를 작성해야 했었다.

하지만 C++ 20 부터는 새로운 개념이 생겼다.

바로 Concept 이다. 이를 이용하여 템플릿 매개변수에 제약을 걸 수 있게 된다.

 

사용방법에는 4가지가 있다.

예제로 정수 타입만 받아서 출력하는 함수 코드를 작성해보았다.

 

1) Requires Clause

template<typename T>
requires std::integral<T>
void TestConcept(T number)
{
    cout << number << endl;
}

 

 

2) Trailing Requires Clause (뒤에 붙는~)

template<typename T>
void TestConcept2(T number) requires std::floating_point<T>
{
    cout << number << endl;
}

 

 

3) Constrained Template Parameter (강요된)

template<std::integral T>
void TestConcept3(T number)
{
    cout << number << endl;
}

 

 

4) Abbreviated Function Template

void TestConcept4(std::integral auto number)
{
    cout << number << endl;
}

 

 

 

이런 식으로 제약을 건 조건에 부합하는 매개변수만 오류가 발생하지 않는다.

이를 이용해서 맨처음 C#으로 작성된 코드를 C++로 작성해보면 아래와 같다.

 

 

 

 

그리고 Concept은 내가 필요한 조건으로 만들어 줄 수도 있다.

 

template<typename T> //정수가 아니고 GameObject를 상속받았어야 함.
concept MyConcept = !std::is_integral_v<T> && std::derived_from<T, GameObject>;

 

template<typename T> //a+b가 가능해야 함.
concept Addable = requires(T a, T b)
{
    a + b; 
};

 

template<typename T>  //비교를 할 수 있어야함. (== 또는 !=)
concept Equality = requires(T a, T b)
{
    {a == b} -> std::convertible_to<bool>;
    {a != b} -> std::convertible_to<bool>;
};

 

template<typename T>
concept Integral = std::is_integral_v<T>;

template<typename T>
concept SignedInt = Integral<T> && std::is_signed_v<T>;

미리 정의된 Concept

 

이름 설명
std::three_way_comparable<T, U> <=>연산자
  a <=> b 일때 a가 작으면 -1, 같으면 0, a가 크면 1을 리턴합니다. 

다음의 조건을 만족하는지 체크합니다. 
1. (a <=> b == 0) ==  bool(a == b)가 true
2. (a <=> b != 0) ==  bool(a != b)가 true
3. ( (a <=> b) <=> 0) 와 ( 0 <=> (a <=> b) )가 상등(equal)
4. (a <=> b < 0) ==  bool(a < b)가 true
5. (a <=> b > 0) ==  bool(a > b)가 true
6. (a <=> b <= 0) ==  bool(a <= b)가 true
7. (a <=> b >= 0) ==  bool(a >= b)가 true
std::same_as<T, U> 두 형식이 같은지 체크
std::derived_from<T, U> template<class _Derived, class _Base> 형식의 콘셉트
첫번째 인자가 두번째 인자의 파생 형식인지 체크
std::convertible_to<T, U> template <class _From, class _To> 형식의 콘셉트
첫번째 인자가 두번째 인자로 변환이 가능하지 체크
std::convertible_to<char* , std::string> : true 
std::convertible_to<std::string, char*> : false
std::common_reference_with<T, U> 두 형식을 어떤 공통의 참조 형식으로 변환 할 수 있음
std::common_reference_with<T, U>일 때 T, U가 어떤 형식 참조형식인 C로 변환 가능 체크
std::common_with<T, U> std::common_reference_with 비슷한데 
참조형식이 아니고 값 형식이여도 가능
std::assignable_from<T, U>  std::assignable_from<_LTy, _RTy>
_LTy이 참조 형식이어야 하고 _RTy을 _LTy으로 배정 할 수 있어야 합니다.
std::swappable<T, U> 두 형식의 값을 교환 할 수 있음
std::integral<T> 정수 형식(char, short, int, long, unsigned 형식)
std::signed_integral<T> 부호 있는 정수 형식(char, short, int, long,)
std::unsigned_integral<T> 부호 없는 정수 형식(unsigned + char, short, int, long,)
std::floating_point<T> 부동 소수점 형식(float, double, long double)
std::destructible<T> 소멸자 사용 가능 여부
std::constructible_from<T, ...Args> std::constructible_from<_Ty, ... _ArgTys> 형식으로 _Ty 객체를 생성할 수 있는지 체크
std::default_initializable<T> 객체 기본 생성자 호출 가능 여부
std::move_constructible<T> 객체 이동 생성자 호출 가능 여부
std::copy_constructible<T> 객체 복사 생성자 호출 가능 여부
std::equality_comparable<T> 객체 상등 비교 가능 여부
std::totally_ordered<T> 전 순서 집합 가능 여부
std::moveable<T> 이동 가능 여부
is_object_v && move_constructible && assignable_from<T&, T> && swappable
std::copyable<T> 복사 가능 여부
copy_constructible && movable && assignable_from<T&, T&>, <T&, const T> <T&, const T&>
std::semiregular<T> 준 정규 형식 여부
copyable && default_initializable
std::regular<T> 정규 형식 여부
semiregular && equality_comparable
std::invocable<F, ...Args> std::invoke를 호출 할 수 있는지 여부
std::regular_invocable<F, ...Args> invocable에 상등을 보존하고 함수 인수들을 수정하지 않습니다.
std::predicate<F, T, U> invocable하며 bool 값을 돌려 줍니다.
std::input_iterator<It> 입력 반복자
std::output_iterator<It, T> 출력 반복자
std::forward_iterator<It> 순방향(전진) 반복자
std::bidirectional_iterator<It> 양방향 반복자
std::random_access_iterator<It> 임의 접근 반복자
std::contiguous_iterator<It> 연속 반복자
연속 반복자를 지원하려면 컨테이너 요소들을 메모리에 연속해서 저장 해야 합니다.
(std::array, std::vector, std::string)
std::permutable<It> 요소들이 제자리 순서 변경이 가능함
std::forward_iterator 
std::mergeable<It1, It2, Out> 정렬된 순차열들을 병합해서 출력 순차열로 산출 할 수 있음
std::sortable<It> 요소들의 순서를 변경해서 정렬된 순차열을 만들 수 있음
반응형

'C++' 카테고리의 다른 글

C++ 20 : Range(중요)  (0) 2024.05.15
C++ 20 : Module(중요)  (0) 2024.05.14
C++ 20  (0) 2024.05.14
lvalue, rvalue  (0) 2024.01.05
c++ 람다  (0) 2023.02.07