질문 (및 대부분의 답변) 이이 결함 보고서의 해결책에 게시 된 이후 표준이 변경되었습니다 .
for(:)
타입에 루프 를 적용하는 방법 X
은 이제 두 가지 방법 중 하나입니다.
멤버를 X::begin()
만들고 X::end()
반복자처럼 작동하는 것을 반환
무료 함수를 작성 begin(X&)
하고 end(X&)
당신의 유형과 같은 네임 스페이스에, 반복자 같은 역할을 돌려 무언가를 X
.¹
그리고 유사점도 비슷합니다 const
. 이것은 결함 보고서 변경을 구현하는 컴파일러와 그렇지 않은 컴파일러 모두에서 작동합니다.
반환 된 객체는 실제로 반복자 일 필요는 없습니다. for(:)
루프는 C ++ 표준의 대부분의 지역 달리한다 뭔가 동등한로 확대 지정 :
for( range_declaration : range_expression )
된다 :
{
auto && __range = range_expression ;
for (auto __begin = begin_expr,
__end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
로 시작하는 변수는 곳 __
에서만 박람회이며, begin_expr
그리고 end_expr
마법입니다 전화 begin
/ end
.²
begin / end 반환 값에 대한 요구 사항은 간단합니다. pre-를 오버로드 ++
하고, 초기화식이 유효한지, !=
부울 컨텍스트에서 사용할 수있는 이진 , *
할당 초기화 할 수있는 항목을 반환 하는 이진 range_declaration
, 공개를 노출해야합니다. 파괴 장치.
반복자와 호환되지 않는 방식으로 그렇게하는 것은 아마도 나쁜 생각입니다 .C ++의 향후 반복은 코드를 깨는 것에 대해 상대적으로 무심 할 수 있기 때문입니다.
제쳐두고, 표준의 향후 개정이와 end_expr
다른 유형을 반환 하도록 허용 할 가능성이 상당히 높다 begin_expr
. 이 기능은 손으로 쓴 C 루프만큼 효율적으로 최적화하기 쉬운 "게으른 끝"평가 (널 종료 감지와 같은) 및 기타 유사한 이점을 허용한다는 점에서 유용합니다.
¹ for(:)
루프는 임시 auto&&
변수를 변수 에 저장 하고이를 lvalue로 전달합니다. 임시 (또는 다른 rvalue)를 반복하는지 감지 할 수 없습니다. 이러한 과부하는 for(:)
루프에 의해 호출되지 않습니다 . n4527의 [stmt.ranged] 1.2-1.3을 참조하십시오.
² 부르는 어느 begin
/ 된 end
방법 또는 ADL 전용 조회없는 기능 begin
/ end
, 또는 C 스타일 배열 지원 마법. 참고 std::begin
않는 호출되지 않습니다 range_expression
다시 표시의 유형의 개체 namespace std
또는 동일에 의존.
에 C ++ 17 범위-표현식이 업데이트되었습니다
{
auto && __range = range_expression ;
auto __begin = begin_expr;
auto __end = end_expr;
for (;__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
의 유형 __begin
과 __end
분리되었습니다.
이를 통해 종료 반복자가 시작과 동일한 유형이 될 수 없습니다. 엔드 이터레이터 유형은 !=
시작 이터레이터 유형 만 지원하는 "센티넬"일 수 있습니다 .
이 유용한 이유의 실제 예는 끝 반복자가 읽기 "당신을 확인할 수 있다는 것입니다 char*
그것을 가리키는 경우로 볼 '0'
때" ==
A를 char*
. 이를 통해 C ++ 범위 표현식은 널 종료 char*
버퍼를 반복 할 때 최적의 코드를 생성 할 수 있습니다.
struct null_sentinal_t {
template<class Rhs,
std::enable_if_t<!std::is_same<Rhs, null_sentinal_t>{},int> =0
>
friend bool operator==(Rhs const& ptr, null_sentinal_t) {
return !*ptr;
}
template<class Rhs,
std::enable_if_t<!std::is_same<Rhs, null_sentinal_t>{},int> =0
>
friend bool operator!=(Rhs const& ptr, null_sentinal_t) {
return !(ptr==null_sentinal_t{});
}
template<class Lhs,
std::enable_if_t<!std::is_same<Lhs, null_sentinal_t>{},int> =0
>
friend bool operator==(null_sentinal_t, Lhs const& ptr) {
return !*ptr;
}
template<class Lhs,
std::enable_if_t<!std::is_same<Lhs, null_sentinal_t>{},int> =0
>
friend bool operator!=(null_sentinal_t, Lhs const& ptr) {
return !(null_sentinal_t{}==ptr);
}
friend bool operator==(null_sentinal_t, null_sentinal_t) {
return true;
}
friend bool operator!=(null_sentinal_t, null_sentinal_t) {
return false;
}
};
완전한 C ++ 17 지원이없는 컴파일러에서의 라이브 예제 ; for
루프 수동 확장.
begin/end
static 또는 free 멤버 또는 친구 를 정의하여 가능합니다begin/end
. 어떤 네임 스페이스에서 무료 기능을 사용하는지주의하십시오 : stackoverflow.com/questions/28242073/…