D2: std.algorithm.indexOf больше не работает - PullRequest
7 голосов
/ 31 марта 2011

Я разместил следующий код на rosettacode.org для задачи преобразования арабских и римских цифр .

import std.regex, std.array, std.algorithm;

immutable {
    int[] weights = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
    string[] symbols = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", 
                        "V", "IV", "I"];
}

string toRoman(int n) {
    auto app = appender!string;
    foreach (i, w; weights) {
        while (n >= w) {
            app.put(symbols[i]);
            n -= w;
        }
        if (n == 0) break;
    }
    return app.data;
}

int toArabic(string s) {
    int arabic;
    foreach (m; match(s, "CM|CD|XC|XL|IX|IV|[MDCLXVI]")) {
        arabic += weights[symbols.indexOf(m.hit)];
    }
    return arabic;
}

Раньше он работал нормально, но теперь я получаю ошибку компилятора.

Ошибка: шаблон std.algorithm.indexOf (псевдоним pred = "a == b ", R1, R2) если (есть (typeof (начинается с! (пред)) (стог сена, игла е)))) не соответствует ни одной функции шаблон объявления

Согласно документации indexOf устарел, и вместо него следует использовать countUntil, но он выдает мне ту же ошибку.

Ответы [ 3 ]

6 голосов
/ 31 марта 2011

Длинная история, но я постараюсь сделать ее короткой:

std.algorithm.indexOf ожидает входной диапазон , который является структурным типом , который должен определять front, popFront() и empty. Для массивов эти методы определены в std.array и работают через единый синтаксис вызова функции, что позволяет fun(someArray) работать так же, как someArray.fun().

immutable string[] не является входным диапазоном, поскольку popFront удаляет первый элемент массива, что нельзя сделать для неизменяемого типа. То, что раньше это работало, было ошибкой.

Я обновил запись кода Розетты, чтобы изменить symbols на immutable(string)[]. Здесь элементы symbols являются неизменяемыми, но массив может быть разрезан и переназначен. Например:

void main() {
    immutable string[] s1 = ["a", "b", "c"];
    immutable(string)[] s2 = ["d", "e", "f"];

    s2 = s2[1..$];  // This is what std.array.popFront does under the hood.
    assert(s2 == ["e", "f"]);  // Passes.
    s2[1] = "g";     // Error:  Can't modify immutable data.

    s1 = s1[1..$];  // Error:  Can't modify immutable data.
    s1[1] = "g";    // Error:  Can't modify immutable data.
}

immutable string[] неявно преобразуется в immutable(string)[], но неявное создание экземпляра шаблона функции (часто обозначаемое как IFTI; это то, что используется для создания экземпляра шаблона indexOf) не достаточно умен, попробуйте это.

4 голосов
/ 31 марта 2011

Я считаю, что это ошибка в std.algorithm.Если вы удалите квалификатор immutable, код будет работать как есть.Я думаю indexOf / countUntil должен работать на immutable массивах, но на данный момент это не так.

Вы можете сделать их константами манифеста (перед каждым объявлением ставится enum) и похоже на работу. Забавно, но это также может быть ошибка .

3 голосов
/ 01 апреля 2011

Извинения за поломку;Я представил это.Я согласен с описанием dsimcha и предложенным исправлением.

Мы рассматриваем простое изменение языка для объяснения этого простого случая.Это автоматически очистит один уровень квалификаторов при передаче значения квалифицированного типа в функцию.Согласно этому (на данный момент гипотетическому) правилу квалификатор (T []) станет (при передаче в функцию) квалификатором (T) [], а квалификатор (T *) станет классификатором (T) *.Это позволит вашему примеру работать.Недостатком является то, что функция не сможет различить квалификатор верхнего уровня, но я считаю, что это не вредит конкретному использованию.

...