concpet란?
- concept는 c++20에서 추가된 것이다. 이것을 사용하는 이유는 몇가지 있는데 대표적으로 template을 사용할 때 에러코드는 길어져서 읽기가 힘든 것이있다. 그렇지만 concept를 이용해서 제약조건을 준다면 에러코드가 명확해지면서 짧아지게된다.
- 또한 requires절과 함수오버로딩을 섞을 수 있다 -> 함수 오버로딩을 하는데 만약 제약조건에서 가상함수 일 경우는 함수a를 사용하고 그렇지않으면 함수 b를 사용하게 하는 경우 적용할 수 있다..
- concept은 --- > a named set of requirements이다.. 이것은 요구조건들의 집합..! 조건을 하나가 아니라 여러개를 둘 수 있다는 의미이다.
기본 문법 예제
template<typename T>
concept GreaterThan4 = sizeof(T) >= 4;
template<typename T> requires GreaterThan4<T>
void foo(T arg)
{
}
//===최대공약수 concept..
//required절을 사용하지 않으면.. 만약 a % b부분이 compile 에러가 발생하는데, 이러한 줄이 여러개라면 오류가 엄청 길어진다..
template<typename T>
T gcd1(T a, T b)
{
return b == 0 ? a : gcd1(b, a % b);
}
// requires 절을 사용해서 gcd2 함수를 찾을 수 없다는 에러를 말한다..
template<typename T> requires std::is_integral_v<T>
T gcd2(T a, T b)
{
return b == 0 ? a : gcd2(b, a % b);
}
int main()
{
int i = 1;
foo(i);
gcd1(4.2, 2.1); //error
}
- 위에서 concept GreaterThan4 = sizeof(T) >= 4; 이라고 GreaterThan4는 크기가 4이상인 것이다. 이것을 이용해서 제약조건을 줄 수 있다.
- 밑의 foo함수에서 requires 뒤에 제약 조건이 concept으로 만든 GraterThan4이다..
- 그리고 gcd함수 두개를 보면 에러코드가 짧아진다는 예를 확인할 수 있다..
requires clauses과 함수 오버로딩.. (가상함수버전 적용)
class Test
{
public:
virtual void foo() {}
};
template<typename T> requires std::is_polymorphic_v<T>
void foo(const T& arg)
{
cout << "가상함수 버전" << endl;
}
template<typename T> requires (!std::is_polymorphic_v<T>)
void foo(const T& arg)
{
cout << "No 가상함수 버전" << endl;
}
int main()
{
foo(Test());
}
- 또한 requires 절을 이용할 때 type_traits를 같이 사용하면 제약조건을 주기가 좋은데, 위에서 std::is_polymorphic_v를 사용하면 T가 가상함수인지 아닌지 파악이 가능하다...
- 참고로 requires 절에는 bool값으로 파악이 가능한 상수가 가능하다.. !!
requires clauses과 함수 오버로딩.. (iteraotr 임의접근, 순차접근 적용)
template<typename T> requires std::random_access_iterator<T>
void advance(T& p, int n)
{
cout << "임의 접근" << endl;
p = p + n;
}
template<typename T> requires std::input_iterator<T>
void advance(T& p, int n)
{
cout << "임의 접근이 아닌 경우" << endl;
while (n--) ++p;
}
int main()
{
std::vector c = { 1, 2, 3, 4, 5, 6, 7 }; //vector는 임의접근이랑 input_iterator 둘다 가능
std::list cc = { 1, 2, 3, 4, 5, 6, 7 }; //input_iterator만 가능..
auto p = std::begin(c);
advance(p, 5);
return 0;
}
- 위에서 requires절을 이용한 함수오버로딩을 볼 수 있다. 여기서 std::input_iterator 와 std::random_access_iterator도 type_trais에 있는 것이다.. !
concept의 a named set of requirements 예시.
template<typename T>
concept Integral = std::is_integral_v<T>;
//concept require절을 사용할때 template파라미터 옆에 사용해도 되지만 foo(T a) 옆에 사용해도된다.. !
template<typename T> requires Integral<T>
void foo(T a)
{
}
- 위에서 컨셉을 정의하였다. 컨셉의 이름은 Integral 이것은 정수만 받을 수 있다...
- 여러개의 제약 조건을 하나의 이름으로 표현가능하다 std::is_integral_v 뒤에 &&로 늘어놔도 동일하다...
requires_expression
template<typename T> concept Integral = std::is_integral_v<T>;
template<typename T> concept True = true;
// requires expression -> concept를 만들 때 사용하는 표현식 !
template<typename T>
concept Modulus = requires(T a, T b)
{
a% b;
};
//requires clauses requires뒤에 제약조건을 준다..
template<typename T> requires Modulus<T>
T Mod(T a, T b)
{
return a % b;
}
int main()
{
Mod(10, 3);
}
- 위에서 requires_expression을 보여주고있다.
- requires_expression는 concept을 만들 때 사용하면 표현식이다.
- 위에서 Modulus는 임의의 타입 a, b가 %가 가능해ㅑㅇ한다는 것이다.
requires_expression2
requires_expression의 기본 문법..
requires { requirement-seq};,
requires (parameter-list) {requirement_seq};...
requires 후에 바로 문맥이 와도 되고 아니면, parameter-list가 있어도된다...
다양한 예시를 보자.
template<typename T>
concept LessThanComparable1 = requires(T a, T b)
{
a < b;
};
template<typename T>
concept LessThanComparable2 = requires(T a, T b)
{
{a < b} -> std::convertible_to<bool>; // convertible_to는 concept안에 있어야한다.. , {a < b} 결과가 <bool>로 변환이 가능해야한다..
};
template<typename T>
concept Equality = requires(T a, T b)
{
{a == b} -> std::convertible_to<bool>;
{a != b} -> std::convertible_to<bool>;
};
//Container라는 concept을 만드는데 그것은 begin()이랑 end()를 사용할 수 있어야한다..
template<typename T>
concept Container = requires(T c)
{
c.begin();
c.end();
};
template<typename T>
concept HasValueType = requires
{
typename T::value_type;
};
template<typename T> requires Container<T>
void foo(T a) {}
template<typename T> requires HasValueType<T>
void goo(T a) {}
int main()
{
vector<int> v = { 1, 2, 3 };
foo(v);
goo(v);
// foo(1);
//goo(1);
return 0;
}
- 위에서 LessThanComparable1는 requires가 오고 뒤에 파라미터가 온 뒤 해당 변수들이 a < b를 만족해야한다는 표현식이다..
- LessThanComparable2에는 convertible_to가 사용되었다.. 이것은 #include
안에 존재한다... 뜻은 {a < b} 결과가 로 변환이 가능해야한다..
'c++ > 모던c++' 카테고리의 다른 글
meta template(moden c++ 방법) (0) | 2022.05.23 |
---|---|
using template, variable template (0) | 2022.05.23 |
varidic template (가변인자.. tuple직접구현..) (0) | 2022.05.22 |
c++ 11 가변인자템플릿 varidic template (0) | 2022.04.07 |
전달 참조 forwarding reference (c++17) (0) | 2022.03.29 |