투명 비교기 란 무엇입니까?


106

C ++ 14에서 연관 컨테이너는 C ++ 11에서 변경된 것 같습니다 – [associative.reqmts] / 13은 다음과 같이 말합니다.

멤버 함수 템플릿은 find, count, lower_bound, upper_bound,와 equal_range유형이하지 않는 오버로드 확인에 참여하지 않는다 Compare::is_transparent존재한다.

비교기를 "투명하게"만드는 목적은 무엇입니까?

C ++ 14는 다음과 같은 라이브러리 템플릿도 제공합니다.

template <class T = void> struct less {
    constexpr bool operator()(const T& x, const T& y) const;
    typedef T first_argument_type;
    typedef T second_argument_type;
    typedef bool result_type;
};

template <> struct less<void> {
    template <class T, class U> auto operator()(T&& t, U&& u) const
    -> decltype(std::forward<T>(t) < std::forward<U>(u));
    typedef *unspecified* is_transparent;
};

그래서 예를 들어, std::set<T, std::less<T>>없는 투명한 비교기를 가지고 있지만,std::set<T, std::less<>> 하나가있다.

이로 인해 어떤 문제가 해결되고 표준 컨테이너의 작동 방식이 바뀌나요? 예를 들어,의 템플릿 매개 변수는 std::set여전히 Key, Compare = std::less<Key>, ...너무 기본 설정은 잃지 않는, find, count, 등 회원?


예를 들어이 cppreference 설명을 참조하십시오 . 나는 단어 "멤버 함수에 주목하고 있습니다 때문에 나는 지금 바보 같은 기분 템플릿 ..."
Kerrek SB

5
관련 가능성이있는 경우 : stackoverflow.com/questions/18939882/…

cppreference도에 추천 광고를 가지고 en.cppreference.com/w/cpp/utility/functional/less_void
Cubbi

답변:


60

이것은 어떤 문제를 해결합니까?

Dietmar의 답변remyabel의 답변을 참조하십시오 .

이것이 표준 컨테이너의 작동 방식을 바꾸나요?

아니요, 기본적으로는 아닙니다.

findetc. 의 새 멤버 함수 템플릿 오버로드 를 사용하면 키 유형 자체를 사용하는 대신 컨테이너의 키와 비교할 수있는 유형을 사용할 수 있습니다. 이 기능을 추가하기위한 근거와 상세하고 신중하게 작성된 제안은 Joaquín Mª López Muñoz의 N3465 를 참조하십시오 .

브리스톨 회의에서 LWG는 이기종 조회 기능이 유용하고 바람직하다는 데 동의했지만 Joaquín의 제안이 모든 경우에 안전 할 것이라고 확신 할 수 없었습니다. N3465 제안은 일부 프로그램에 심각한 문제를 일으켰을 것입니다 ( 기존 코드에 대한 영향 섹션 참조). Joaquín은 LWG가 장단점을 이해하는 데 도움이되는 몇 가지 대체 구현으로 업데이트 된 초안 제안을 준비했습니다.이 제안은 LWG가 장단점을 이해하는 데 매우 유용했지만, 모두 어떤 식 으로든 일부 프로그램을 깨뜨릴 위험이 있으므로 기능을 추가 할 합의가 없었습니다. 우리는 기능을 무조건 추가하는 것이 안전하지는 않지만 기본적으로 비활성화되고 "옵트 인"만하면 안전하다고 결정했습니다.

N3657 제안 ( 나와 N3465를 기반으로 한 STL 및 나중에 Joaquín이 게시하지 않은 초안) 의 마지막 순간 수정 의 주요 차이점은 유형을 새 기능에 옵트 인하is_transparent데 사용할 수있는 프로토콜로 추가하는 것입니다.

"투명한 펑터"(즉, is_transparent유형 을 정의하는 펑터)를 사용하지 않는 경우 컨테이너는 항상 해왔 던 것과 동일하게 동작하며 여전히 기본값입니다.

std::less<>(C ++ 14의 새로운 기능) 또는 다른 "투명한 펑터"유형 을 사용하도록 선택 하면 새로운 기능을 사용할 수 있습니다.

std::less<>별칭 템플릿을 사용하면 쉽게 사용할 수 있습니다.

template<typename T, typename Cmp = std::less<>, typename Alloc = std::allocator<T>>
  using set = std::set<T, Cmp, Alloc>;

이름 is_transparent은 C ++ 14에 "다이아몬드 연산자"를 추가 한 STL의 N3421에서 유래되었습니다. "투명한 펑터"는 모든 인수 유형 (동일 할 필요는 없음)을 받아들이고 해당 인수를 다른 연산자에 전달하는 것입니다. 이러한 펑 터는 연관 컨테이너에서 이기종 조회에 대해 정확히 원하는 것이기 때문에 유형 is_transparent이 모든 다이아몬드 연산자에 추가되고 연관 컨테이너에서 새 기능이 활성화되어야 함을 나타내는 태그 유형으로 사용되었습니다. 기술적으로 컨테이너에는 "투명한 펑터"가 필요하지 않습니다. 이종 유형으로 호출을 지원하는 하나만 있으면됩니다 (예 : https://stackoverflow.com/a/18940595/981959pointer_comp유형을 사용하여 문제를 해결하는 데 사용할 수 있음). ). STL의 정의에 따라 투명하지 않습니다.pointer_comp::is_transparentstd::set<T, C> 유형의 키 T또는 int다음 C유일한 유형의 인수를 호출 할 필요가 Tint(중 순서대로), 그것은 진정으로 투명 할 필요는 없습니다. 우리는 더 나은 이름을 만들 수 없었기 때문에 부분적으로 그 이름을 사용했습니다 ( is_polymorphic이러한 펑 터는 정적 다형성을 사용하기 때문에 선호 했지만 std::is_polymorphic동적 다형성을 참조 하는 유형 특성이 이미 있습니다 ).


3
이봐 요, 당신은 STL이 "물론 당신의 머릿속에서 템플릿 인수 추론을 할 수 있습니다"라고 말한 사람 이었습니까?
Kerrek SB

10
아니, 내가 거기 아니었지만, 훨씬 더 내가 :) 것보다 그들의 머리에서 컴파일러를 따르는 사람들이있다
조나단 Wakely

<>링크 된 제안에서 "다이아몬드 연산자"가 언급 된 것 같지만 그 제안은 소개되지 않았습니다 <>. 빈 템플릿 매개 변수 목록에 대한 기존 구문입니다. "Diamond operator functors"는 좀 덜 혼란 스러울 것입니다.
Qwertie

33

C ++ 11에서 멤버 템플릿이없는 find(), lower_bound()등 즉, 아무 것도 이러한 변화에 의해 손실되지 않습니다. 멤버 템플릿은 n3657과 함께 도입되어 연관 컨테이너에서 이기종 키를 사용할 수 있습니다. 좋고 나쁜 예를 제외하고 이것이 유용한 구체적인 예는 보이지 않습니다!

is_transparent사용은 원치 않는 변환을 방지하기위한 것입니다. 멤버 템플릿이 제한되지 않은 경우 기존 코드는 멤버 템플릿없이 변환되었을 객체를 직접 통과 할 수 있습니다. n3657의 예제 사용 사례 std::set<std::string>는 문자열 리터럴을 사용하여 객체를 찾는 것 입니다. C ++ 11 정의 std::string를 사용하면 문자열 리터럴을 해당 멤버 함수에 전달할 때 객체가 생성됩니다. 변경으로 문자열 리터럴을 직접 사용할 수 있습니다. 기본 비교 함수 개체가 독점적으로 구현 되면 각 비교에 대해 std::stringa std::string가 생성 되기 때문에 나쁘다 . 반면에 기본 비교 함수 객체가std::string 임시 개체의 생성을 피할 수있는 문자열 리터럴.

is_transparent비교 함수 개체 의 중첩 형식은 템플릿 멤버 함수를 사용해야하는지 여부를 지정하는 방법을 제공합니다. 비교 함수 개체가 이기종 인수를 처리 할 수있는 경우이 형식을 정의하여 다른 인수를 효율적으로 처리 할 수 ​​있음을 나타냅니다. 예를 들어, 새로운 연산자 함수 객체는 단지 위임하고 operator<()투명하다고 주장합니다. 적어도 그것은 인수로 std::string취하는 연산자보다 덜 오버로드 된 작업입니다 char const*. 이러한 함수 객체도 새롭기 때문에 잘못된 작업을 수행하더라도 (예 : 특정 유형에 대한 변환이 필요함) 적어도 조용히 변경되지 않아 성능이 저하됩니다.


감사합니다-다른 질문에 대한 내 의견을 참조하십시오. 기본적으로 투명한 동작을 얻습니까?
Kerrek SB

8
@KerrekSB : is_transparent23.2.4 [associative.reqmts] 단락 13에 따라 비교 함수 개체에 정의 된 경우 투명 동작이 활성화됩니다 . 기본 비교 함수 개체는 std::less<Key>23.4.2 [associative.map.syn] 및 23.4에 따릅니다. 3 [associative.set.syn]. 20.10.5 [비교] 제 4 일반적인 템플릿에 따르면 대한 std::less<...>않는 하지 중첩 유형을 정의 is_transparent하지만 std::less<void>특성화한다. 즉, 기본적으로 투명 연산자가 없습니다.
Dietmar Kühl

명명에 대한 아이디어가 있습니까? 내 말은 왜 is_transparent?
plasmacel

"이것이 유용한 구체적인 예"를 원하십니까? 여기 내 사용 사례
spraff

19

다음은 n3657의 모든 복사 파스타입니다 .

Q. 비교기를 "투명하게"만드는 목적은 무엇입니까?

A. 연관 컨테이너 조회 함수 (find, lower_bound, upper_bound, equal_range)는 key_type의 인수 만 취하며 조회를 수행하려면 사용자가 key_type의 객체를 (암시 적 또는 명시 적으로) 구성해야합니다. 이는 비용이 많이들 수 있습니다. 예를 들어 비교기 기능이 객체의 한 필드 만 볼 때 집합에서 검색 할 큰 객체를 구성하는 경우가 있습니다. 사용자들 사이에서는 key_type에 필적하는 다른 유형을 사용하여 검색 할 수 있다는 강한 욕구가 있습니다.

Q. 어떤 문제가 해결됩니까?

A. LWG는 다음과 같은 코드에 대해 우려했습니다.

std::set<std::string> s = /* ... */;
s.find("key");

C ++ 11에서는 단일 std :: string 임시를 생성 한 다음 키를 찾기 위해 요소와 비교합니다.

N3465에 의해 제안 된 변경으로 std :: set :: find () 함수는 const char *를 비교기 함수 std :: less로 전달하는 제한되지 않은 템플릿이되어 std :: string 임시를 생성합니다. 모든 비교. LWG는이 성능 문제를 심각한 문제로 간주했습니다. 템플릿 find () 함수는 포인터 컨테이너에서 NULL을 찾는 것을 방지하여 이전에 유효한 코드가 더 이상 컴파일되지 않게했지만, 이는 조용한 성능 회귀보다 덜 심각한 문제로 간주되었습니다.

Q. 이것이 표준 컨테이너 작동 방식을 변경합니까?

A.이 제안은 멤버 함수 템플릿으로 조회 멤버 함수를 오버로드하여 연관 컨테이너를 수정합니다. 언어 변경이 없습니다.

Q. 기본 세트는 찾기, 개수 등을 잃습니다.

A. 새 C ++ 14 라이브러리 기능이 비교 함수로 사용되지 않는 한 멤버 함수가 존재하지 않기 때문에 기존의 거의 모든 C ++ 11 코드는 영향을받지 않습니다.

Yakk 를 인용하려면 ,

C ++ 14에서는 Compare :: is_transparent가 있으면 std :: set :: find가 템플릿 함수입니다. 전달하는 유형은 키일 필요가 없으며 비교기에서 동일합니다.

및 n3657,

23.2.4 [associative.reqmts]에 단락 13 추가 : find, lower_bound, upper_bound 및 equal_range 멤버 함수 템플릿은 Compare :: is_transparent 유형 이 존재 하지 않는 한 오버로드 해결에 참여 하지 않습니다.

n3421"Transparent Operator Functors" 의 예를 제공합니다 .

전체 코드는 여기에있다 .


1
않습니다 std::set<std::string>실제로 "통과 혜택을 char const *통해"을, 또는 당신이 할 필요합니까 std::set<std::string, std::less<>>?
Kerrek SB

@Kerrek 내가 착각하지 않았다면 "char const * 전달"이 그들이 피하려고했던 문제라고 생각합니다. 문구를보세요 :With the change proposed by N3465 the std::set::find() function would be an unconstrained template which would pass the const char* through to the comparator function, std::less<std::string>, which would construct a std::string temporary for every comparison. The LWG considered this performance problem to be a serious issue.

귀하의 인용문과 단락 13의 내 말은 "유형이 존재하지 않는 한 / 존재하지 않는 한"...?!
Kerrek SB

4
@KerrekSB, 그게 내 잘못입니다. N3657은 "존재한다"라고 말해야했지만 "존재하지 않는다"라고 썼습니다. 마지막 순간에 작성된 늦은 논문이었습니다. 초안 표준이 정확합니다.
Jonathan Wakely

3
그래, 내가 무엇을 인용 명확 수 있습니다 의미 실제로 :) 시간에 말하지 무슨 말을하는
조나단 Wakely

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.