2015-02-03 8 views
4

나는 클래스 기반의 유한 랜덤 액세스 범위에서 작업 해왔다. 4838 | | 오류 "algorithm.d : foreach는 : 전자 심판을 할 수 없습니다 그것에 몇 가지 검사를 수행 할 때 :std.algorithm.find가 범위 요소에 대한 참조를 요구해야합니까?

auto myRange = /* construct my range */ 
static assert (isRandomAccessRange!(typeof(myRange))); // 
static assert (!isInfinite!(typeof(myRange)));   // both pass 
auto preamble = myRange[0..128]; 
assert(all!"a == 0"(preamble)); // check for all zeros 

나는 위의 코드 조각의 마지막 줄에 관한, GDC 4.9.2이 컴파일 오류가 발생했습니다 "

실제로 foreach 각 요소에 대한 참조 소요 std.algorithm.find에서이 코드 조각합니다 (find_if 변형, 범위와 조건을 고려)에 오류 점 :

InputRange find(alias pred, InputRange)(InputRange haystack) 
if (isInputRange!InputRange) 
{ 
    alias R = InputRange; 
    alias predFun = unaryFun!pred; 
    static if (isNarrowString!R) 
    { 
     ... 
    } 
    else static if (!isInfinite!R && hasSlicing!R && is(typeof(haystack[cast(size_t)0 .. $]))) 
    { 
     size_t i = 0; 
     foreach (ref e; haystack) // <-- needs a ref 
     { 
      if (predFun(e)) 
       return haystack[i .. $]; 
      ++i; 
     } 
     return haystack[$ .. $]; 
    } 
    else 
    { 
     ... 
    } 
} 

이 가능성이 가장 높은 발생을 내가 제공했기 때문에 ref 인수를 제공하지 않는 opApply 구현 (클래스는 다른 멤버 함수에 ref 반환 유형을 제공하지 않음).

int opApply(int delegate(E) f) {...} 
int opApply(int delegate(size_t,E) f) {...} 

는 그 변경,하지만 정말 날 귀찮게하는 것은 지금 범위 클래스는 함수의 전제 조건에 부합하며, foreach 반복이 여전히 어쨌든 그들과 함께 작업해야한다는 것입니다 수 있습니다. 문서에서 인용 :

이들 모두가 제공되었지만 (그렇지 않은 경우 무작위 액세스 범위가 아닐 수 있습니다.) 따라서이를 사용해야합니다. 대신, 다음에 설명하는 대체 반복 방법을 찾고있을 수 있습니다.

If the aggregate expression is a struct or class object, and the range properties do not exist, then the foreach is defined by the special opApply member function and the foreach_reverse behavior is defined by the special opApplyReverse member function. These functions have the type:

int opApply(int delegate(ref Type [, ...]) dg);

내 해석에 따르면 안되는 것은 아닙니다.

또한 std.algorithm.all을 인용 한 참고 문헌에 대한 반복을 요구하지 않는 것 중 하나

bool all(Range)(Range range) if (isInputRange!Range && is(typeof(unaryFun!pred(range.front))));

Returns true if and only if all values v found in the input range range satisfy the predicate pred. Performs (at most) Ο(range.length) evaluations of pred.

그래서이 포보스 라이브러리의 버그이며, std.algorithm.find는 처음부터 값으로 반복해야

? 아니면 제가 놓친 뭔가가 있습니까?

답변

1

심지어 그 다음 범위 기반 기능 foreach하지 opApply에 사용되는 범위, 만약 때문에 감각, 범위해야하는데 객체에 opApply을 선언하지 않습니다.이 front, popFrontempty 대신 범위 유형에서 호출되는 경우 확실히 컴파일러 버그입니다. 이 사운드에서 opApplyref을 사용하지만 front은 사용하지 않으므로 컴파일러는 opApply을 잘못 선택합니다. 그러나 frontrefforeach이고 ref을 사용하지 않는 한 정상적으로 작동하며 opApply이 선언되지 않은 한 올바르게 작동합니다. 따라서 refopApplyref이고 front이있는 경우 컴파일러가 opApply을 잘못 사용한다는 사실만큼 문제가되지 않습니다.

따라서 컴파일러를 수정해야하지만 이전에 잡히지 않았을 것입니다. opApply을 범위 형식에 선언하는 것은 의미가 없기 때문입니다. 그래서, 범위 형식에 opApply을 선언하지 않도록 코드를 변경해야한다고 주장합니다. 그렇다면이 특정 버그에 부딪치지 않을 것입니다.이 반복 할 때 haystacksave에 호출하지 못하기 때문에, 상기 되 그게

는 포보스 에서 해당 코드 (종류 등) 참조 종류에 대한 범위 버이다. 결과는 원래 범위가 검색되는 지점을 참조하도록 변경되는 반면 반환되는 요소는 건초 더미의 앞쪽에서 정확한 지점을 지나서 가리킨다는 것입니다. 따라서 opApply 선언을 중지하거나 컴파일러 버그가 수정되면 해당 범위에 대한 참조 유형을 사용하는 경우 코드가 작동하기 시작하도록 std.algorithm.find를 수정해야합니다.

편집 :

좋아요. 그건 옳지 않아. 일부 컴파일러 개발자와 논의 할 때 수정되었습니다. 예전에는 범위 함수가 opApply 이상 이었지만 스펙에서 말하는 것입니다. 그러나 어떤 경우에는 opApply이 범위 함수보다 선호되어 opApply을 사용하여 범위 유형을 반복 할 수 있도록 변경되었습니다. foreach (분명히 범위 기능의 위험을 초래하고 실제로는 더러운 버그를 초래할 수있는 동일한 동작을하지 않는 opApply). 그래서, 사양은 현재 컴파일러의 동작과 일치하지 않으며, opApply을 범위 형식으로 선언해야합니다 (비록 명확한 성능 향상을 얻지 못한다면 아직 조언 할 것이지만opApply을 선언해야합니다.).

사실, 여기서 오류가 발생한다는 사실은 여전히 ​​컴파일러 버그입니다. opApplyref을 사용하지 않으므로 ref 루프 변수에서는 작동하지 않습니다. 반면 범위 함수는 그렇기 때문에 컴파일러가이 경우 범위 함수를 호출해야하며 분명히 그렇지 않습니다. 어쨌든, 이것은 이전에 잡히지 않았습니다. 왜냐하면 거의 아무도 범위에서 opApply을 사용하지 않았기 때문입니다. 그렇게하는 유일한 이유는 성능 향상이있는 경우이고, 스펙이 여전히 그렇게 말하고 있다는 것입니다. 범위 기능은 opApply보다 선호되어 더 적은 수의 사람들이 그렇지 않은 경우보다 시도했습니다.

+0

실제로, 그것은 그것을 못 박았습니다. D 커뮤니티는 이와 같은 결함을 찾기 위해 좀 더 우둔한 프로그래머를 사용할 수도 있습니다. ;) –