개념의 양화는 개선인가, 나쁜 습관인가?
개념에 람다를 넣은 다음 코드를 작성할 수 있습니다. 이것을 예로 들어 보겠습니다. 나는 이러한 개념에 대한 표준 개념을 선호하며 이것은이 예제의 목적만을위한 것임을 명심하십시오-godbolt
template<class T>
concept labdified_concept =
requires {
[](){
T t, tt; // default constructible
T ttt{t}; // copy constructible
tt = t; //copy assignable
tt = std::move(t); // move assignable
};
};
대신에:
template<class T>
concept normal_concept =
std::default_initializable<T> && std::movable<T> && std::copy_constructible<T>;
양육 화는 개선인가 나쁜 습관인가? 가독성 지점에서도.
답변
이것은 유효하지 않아야합니다. 평가되지 않은 컨텍스트로 허용되는 람다의 요점은 문에서 SFINAE를 갑자기 허용하는 것이 아닙니다.
[temp.deduct] / 9 에는이를 명확히하는 몇 가지 문구가 있습니다 .
람다 표현 기능 유형이나 템플릿 매개 변수에 나타나는 템플릿 인수 공제의 목적에 대한 즉각적인 환경의 일부로 간주되지 않습니다. [ 참고 : 의도는 임의의 명령문과 관련된 대체 실패를 처리하기 위해 구현을 요구하지 않는 것입니다. [ 예 :
template <class T> auto f(T) -> decltype([]() { T::invalid; } ()); void f(...); f(0); // error: invalid expression not part of the immediate context template <class T, std::size_t = sizeof([]() { T::invalid; })> void g(T); void g(...); g(0); // error: invalid expression not part of the immediate context template <class T> auto h(T) -> decltype([x = T::invalid]() { }); void h(...); h(0); // error: invalid expression not part of the immediate context template <class T> auto i(T) -> decltype([]() -> typename T::invalid { }); void i(...); i(0); // error: invalid expression not part of the immediate context template <class T> auto j(T t) -> decltype([](auto x) -> decltype(x.invalid) { } (t)); // #1 void j(...); // #2 j(0); // deduction fails on #1, calls #2
— 끝 예 ] — 끝 참고 ]
요구 사항에 상응하는 것이 없습니다. gcc의 동작은 실제로 예상되는 것입니다.
template <typename T> concept C = requires { []{ T t; }; };
struct X { X(int); };
static_assert(!C<X>); // ill-formed
람다의 본문은 즉각적인 컨텍스트 외부에 있으므로 대체 실패가 아니므로 하드 오류입니다.
이 메커니즘의 명백한 가독성 결함을 무시하면 실제로 작동 하지 않습니다 . 다음을 고려하세요:
template<labdified_concept T>
void foo(T t) {}
template<typename T>
void foo(T t) {}
개념의 규칙은 주어진 T
것이 만족하지 않으면 labdified_concept
다른 하나 foo
가 대신 인스턴스화되어야한다고 말합니다 . 그러나 우리 SS
가 그러한 템플릿을 제공하면 그것은 일어나지 않습니다 . 대신 labdified_concept<SS>
인스턴스화 할 수 없기 때문에 하드 오류가 발생 합니다.
내 물건 requires
표현은 특정 유형의 오류가 요구 사항을 충족하기 위해 실패로 간주 될 수 있도록 특수 처리가 있습니다. 그러나 그 처리는 람다의 본문에는 적용되지 않습니다. 여기에서 형식이 잘못된 코드는 형식이 잘못되어 인스턴스화하려고 할 때 컴파일 오류가 발생합니다.
그리고 그것이 작동하더라도 여전히 작동하지 않습니다. 개념은 개념의 포함에 대한 복잡한 규칙을 가지고 있으므로 다른 개념이 다른 개념보다 더 고도로 전문화 된 것으로 간주 될 수 있습니다. 이를 통해 다른 개념에 대한 오버로딩을 허용 하여 더 제한된 개념을 호출 할 수 있습니다. 예를 들어만을 필요로하는 개념은 default_initializable
필요보다 더 일반적인 것입니다 default_initializable
및 moveable
. 따라서 유형이 두 가지를 모두 충족하면 더 제한적이므로 후자가 사용됩니다.
그러나 이것은 concept
s 에 대한 특별한 규칙 때문에 작동합니다 . 람다에서 요구 사항을 숨기면 이것이 작동하지 않습니다.