2010-03-16 2 views
4

이 코드를 어떻게 수정하겠습니까? 닫힌 범위에서 루핑

template <typename T> void closed_range(T begin, T end) 
{ 
    for (T i = begin; i <= end; ++i) { 
     // do something 
    } 
} 
  • T

    정수 형태로 제한되며, 이러한 종류의 넓게하고 서명 할 수있는 또는 부호

  • begin가 될 수 numeric_limits<T>::min()

  • endnumeric_limits<T>::max() 될 수 (위의 코드에서 ++i이 오버 플로우 됨)

몇 가지 방법이 있지만 아무 것도 없습니다.

+0

<대신 <=? –

+3

@ralu : 질문의 핵심은 <=, <가 아니라는 것입니다. 이것이 닫힌 범위와 반 개방 범위의 차이입니다. –

+0

흥미로운 질문입니다. "size_t i = 10; i> 0; -i)'는'size_t '가 도달 할 수있는 최소값 (unsigned)이기 때문에 의미가 없습니다. –

답변

6

,

template <typename T> void closed_range(T begin, const T end) 
    if (begin <= end) { 
     do { 
      // do something 
     } while (begin != end && (++begin, true)); 
    } 
} 

저주는, 내 첫 번째 시도는 잘못, 위의 수정은 내가 기대했던만큼 꽤하지 않습니다. 에 대해 어떻게 :

template <typename T> bool advance(T &value) { ++value; return true; } 

template <typename T> void closed_range(T first, const T last) 
    if (first <= last) { 
     do { 
      // do something 
     } while (first != last && advance(first)); 
    } 
} 

std::advance 2 개 매개 변수를 사용하기 때문에 T는, 정수 유형이 아닌 경우에도 std::advance에 모호함이 없습니다. 그래서 템플리트는 임의의 이유로 당신이 그것들의 닫힌 범위를 원한다면 예를 들어 랜덤 액세스 반복자와 함께 작동 할 것입니다.

또는 설정 이론이 조금 어때요? 분명히 닫힌 범위에 대해 하나의 루프 만 쓰는 경우 이것은 엄청난 과잉입니다.하지만 당신이 많이하고 싶은 것이 있다면 루프 코드를 올바르게 만듭니다. 확실하지 효율성에 대해 : 당신이 게양되어 endof에 확인 전화를 할 수 있습니다 정말 꽉 루프 :

#include <limits> 
#include <iostream> 

template <typename T> 
struct omega { 
    T val; 
    bool isInfinite; 
    operator T() { return val; } 
    explicit omega(const T &v) : val(v), isInfinite(false) { } 
    omega &operator++() { 
     (val == std::numeric_limits<T>::max()) ? isInfinite = true : ++val; 
     return *this; 
    } 
}; 

template <typename T> 
bool operator==(const omega<T> &lhs, const omega<T> &rhs) { 
    if (lhs.isInfinite) return rhs.isInfinite; 
    return (!rhs.isInfinite) && lhs.val == rhs.val; 
} 
template <typename T> 
bool operator!=(const omega<T> &lhs, const omega<T> &rhs) { 
    return !(lhs == rhs); 
} 

template <typename T> 
omega<T> endof(T val) { 
    omega<T> e(val); 
    return ++e; 
} 

template <typename T> 
void closed_range(T first, T last) { 
    for (omega<T> i(first); i != endof(last); ++i) { 
     // do something 
     std::cout << i << "\n"; 
    } 
} 

int main() { 
    closed_range((short)32765, std::numeric_limits<short>::max()); 
    closed_range((unsigned short)65533, std::numeric_limits<unsigned short>::max()); 
    closed_range(1, 0); 
} 

출력 :

32765 
32766 
32767 
65533 
65534 
65535 

omega<T> 객체에 다른 연산자를 사용하여 약간의주의하십시오. 필자는 데모의 절대 최소값만을 구현했으며 omega<T>은 암시 적으로 T으로 변환되므로 오메가 객체의 "무한 성"을 버릴 수있는 표현식을 작성할 수 있습니다. 산술 연산자의 전체 집합을 선언 (반드시 정의 할 필요는 없음)하여 해결할 수 있습니다. 또는 isInfinite가 true 인 경우 변환에서 예외를 throw합니다. 또는 생성자가 명시 적이기 때문에 우연히 결과를 오메가로 다시 변환 할 수 없다는 사실을 염려 할 필요가 없습니다. 예를 들어 omega<int>(2) < endof(2)은 true이지만 omega<int>(INT_MAX) < endof(INT_MAX)은 false입니다.

5

필자의 의견 : 어쩌면

// Make sure we have at least one iteration 
if (begin <= end) 
{ 
    for (T i = begin; ; ++i) 
    { 
     // do something 

     // Check at the end *before* incrementing so this won't 
     // be affected by overflow 
     if (i == end) 
      break; 
    } 
} 
+1

나는 이것이'assign;으로 좀 더 깔끔해 보입니다. 동안 (테스트) {증가; code}' – Cascabel

+1

@ Jefromi : 무엇을 할당할까요? 다른 방향으로 여전히 오버플로 문제가있는'T i = begin - 1; '이 필요합니다. –

+0

그건 논쟁의 여지가 있습니다. 이 경우 'while'은 중단 조건을 강조하고 'for'는 반복을 강조합니다. 어떤 방법을 사용하든 나머지 방정식을 검색해야합니다. [점진적으로 루프를 끝내거나 루프의 의미를 변경해야합니다]. –

4

이 작동하고 공정하게 분명하다

T i = begin; 
do { 
    ... 
} 
while (i++ < end); 

당신이 스티브 Jessop의 솔루션과 같은 다른 if를 추가 할 필요가 begin >= end의 특별한 경우를 잡으려고합니다

.

+0

+1 : 좋은 깨끗한 솔루션이며, 게다가 세계에서 do-while 루프가 부족합니다. – Cascabel

+1

이 문제는 'T'가 int이고 end가 INT_MAX 인 경우 i 값이 INT_MAX 일 때 'i'를 증가시킵니다. 이는 'i'의 값이 결코 다시 사용되지 않더라도 정의되지 않은 동작입니다. –

+1

공평하게 말해서, 질문자의 코드가 가지고있는 문제에 비해서 작은 문제입니다. * 모든 구현에 잘못되었습니다 .-) –

0

편집 : OP와 더 가깝게 일치하는 재 작업.

#include <iostream> 
using namespace std; 

template<typename T> void closed_range(T begin, T end) 
{ 
    for(bool cont = (begin <= end); cont;) 
    { 
     // do something 
     cout << begin << ", "; 
     if(begin == end) 
      cont = false; 
     else 
      ++begin; 
    } 

    // test - this should return the last element 
    cout << " -- " << begin; 
} 
int main() 
{ 
    closed_range(10, 20); 
    return 0; 
} 

출력은 :

10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 - 20

3
template <typename T, typename F> 
void closed_range(T begin, T end, F functionToPerform) 
{ 
    for (T i = begin; i != end; ++i) { 
     functionToPerform(i); 
    } 
    functionToPerform(end); 
} 
+0

http://codepad.org/4zctR9w5 (Kirill에서 빌린 테스트 장치) – Bill

+0

그리고 여기에서'end'가'numeric_limits :: max()'일 때 : http://codepad.org/6qwwFAVd – Bill

+0

정말, 당신은 이것이 작동한다는 증거가 필요하지 않습니다. C++에서 half-open iteration 스타일은 관용적이므로 복잡한 예제보다 혼란에 덜 여유가 있습니다. –