Updated:

2 minute read

개요

  • Named sets of such requirements
    • 이름을 가진 요구사항의 집합
    • 타입이 가져야 하는 요구사항을 정의하는 문법
  • 제약 조건을 지정
    • 템플릿 인자
    • 변수 선언
  • 제약 조건은 컴파일 타임에 평가
  • 함수 오버로딩이나 템플릿 특수화에서 가장 적절한 함수를 선택하는데 사용
  • 기존에는 템플릿 인자의 타입에만 의존하여 함수 오버로딩 가능
  • concept은 타입뿐만 아니라 속성 혹은 연산자에 따라 함수 오버로딩 가능
  • 런타임에 수행하던 논리 연산들이 컴파일 타임에 결정되어 에러 검출 시점 앞당김 및 실행 속도 향상
  • 컴파일 에러 가동성 증가


concept

  • 문법
    • 정의
       template < template-parameter-list >
       concept concept-name = constraint-expression;
      
    • 사용
      • requires clause
        • 템플릿 선언 뒤에 requires 선언
        • template <typename T> requires over4<T>
      • constrained type template parameter
        • 템플릿 인자에 선언
        • template auto func(T t) {}
      • abbreviated function template declaration
        • 파라미터에 선언
        • auto func(over4 auto t) {}
      • trailing requires clause
        • 함수 선언 뒤에 requires 선언
      • template <typename T> auto func(T t) requires over4<T> {}
    • concepts library
  • 예제
    • 코드
         #include <concepts>
         #include <iostream>
         #include <string>
         #include <type_traits>
              
         using namespace std;
              
         template <typename T>
         concept over4 = sizeof(T) >= 4;
              
         template <typename T>
         requires over4<T>
         auto howToUseConcept_1(T t) { cout << "over4" << endl; }
              
         template <typename T> auto howToUseConcept_1(T t) {
             cout << "not over4" << endl;
         }
              
         template <over4 T> auto howToUseConcept_2(T t) {}
              
         auto howToUseConcept_3(over4 auto t) {}
              
         template <typename T> auto howToUseConcept_4(T t) requires over4<T> {}
              
         template <class T>
         concept integeral = is_integral<T>::value;
              
         int main() {
             howToUseConcept_1(int());
             howToUseConcept_1(short());
              
             cout << integral<int> << endl;
             cout << integral<string> << endl;
              
             auto i1 = int(1);
             over4 auto i2 = int(2);
             // over4 i3 = short();
             cout << i1 << endl;
             cout << i2 << endl;
              
             return 0;
         }
      
    • 실행 결과
         over4
         not over4
         1
         0
         1
         2
      


requires clauses

  • 문법
     template<typename T>
     void f(T&&) requires Eq<T>;
    
  • requires 뒤에는 상수 표현식이여야함
  • 예제
    • 코드
         #include <concepts>
              
         using namespace std;
              
         template <typename T>
         concept over4 = sizeof(T) >= 4;
              
         template <typename T>
         requires over4<T>
         void func(T t) {}
              
         template <typename T>
         requires(sizeof(T) >= 4) void func(T t) {}
              
         template <typename T>
         requires true void func(T t) {}
              
         template <typename T>
         requires false void func(T t) {}
              
         template <typename T>
         requires is_pointer<T>::value void func(T t) {}
              
         constexpr bool check() { return true; }
         template <typename T>
         requires(check()) void func(T t) {}
              
         template <typename T>
         requires is_pointer<T>::value &&(check()) void func(T t) {}
              
         int main() { return 0; }
      


requires expression

  • 문법
     requires { requirement-seq }
                
     requires ( parameter-list(optional) ) { requirement-seq }        
    
  • 예제
    • 코드
         #include <concepts>
         #include <iterator>
         #include <vector>
              
         using namespace std;
              
         template <typename T>
         concept concept_1 = requires {
             typename T::iterator;
         };
         template <concept_1 T> void func1(T t) {}
              
         template <typename T>
         concept concept_2 = requires(T t) {
             t.size();
         };
         template <concept_2 T> void func2(T t) {}
              
         template <typename T>
         concept concept_3 = requires(T t) {
             t.size();
             t.begin();
             t.end();
         };
         template <concept_3 T> void func3(T t) {}
              
         template <typename T>
         concept concept_4 = requires(T t1, T t2) {
             t1 < t2;
             t1 == t2;
             t1 > t2;
         };
         template <concept_4 T> void func4(T t1, T t2) {}
              
         template <typename T1, typename T2>
         concept concept_5 = requires(T1 t1, T2 t2) {
             t1.size();
              
             t2.begin();
             t2.end();
         };
         template <typename T1, typename T2>
         requires concept_5<T1, T2>
         void func5(T1 t1, T2 t2) {}
              
         class Test {
             public:
                 int size() { return 0; }
         };
              
         int main() {
             // func1(int());
             func1(vector<int>{});
              
             // func2(int());
             func2(Test());
             func2(vector<int>{});
              
             // func3(Test());
             func3(vector<int>{});
              
             func4(1, 2);
             func4("a", "b");
             // func4(1, "1");
              
             func5(Test(), vector<int>{});
             // func5(vector<int>{}, Test());
              
             return 0;
         }