Статическая параметрическая функция, специализация в D

Я где-то читал, что D поддерживает специализацию функций для вызовов, где аргументы являются константами времени компиляции. Типичное использование этого - в матричных степенных функциях (если показатель степени равен 2, x*x часто быстрее, чем в общем случае).

Я хочу это в своей функции-члене

   bool opIndexAssign(bool b, size_t i) @trusted pure nothrow in {
        assert(i < len);        // TODO: Add static assert(i < len) when i is constant
    } body {
        b ? bts(ptr, i) : btr(ptr, i);
        return b;
    }

структуры BitSet статического размера, которую я пишу. Это для того, чтобы, когда это возможно, получить ограничения времени компиляции, проверяющие индексную переменную i. я думал

bool opIndexAssign(bool b, const size_t i) @trusted pure nothrow in {
    static assert(i < len);
} body {
    b ? bts(ptr, i) : btr(ptr, i);
    return b;
}

было бы достаточно, но тогда DMD жалуется следующим образом

dmd -debug -gc -gs -unittest -D -Dd/home/per/.emacs.d/auto-builds/dmd/Debug-Boundscheck-Unittest/home/per/Work/justd/ -w -main  ~/Work/justd/bitset.d /home/per/Work/justd/assert_ex.d -of/home/per/.emacs.d/auto-builds/dmd/Debug-Boundscheck-Unittest/home/per/Work/justd/bitset
/home/per/Work/justd/bitset.d(58): Error: bitset.BitSet!2.BitSet.opIndexAssign called with argument types (bool, int) matches both:
    /home/per/Work/justd/bitset.d(49): opIndexAssign(bool b, ulong i)
and:
    /home/per/Work/justd/bitset.d(65): opIndexAssign(bool b, const(ulong) i)
/home/per/Work/justd/bitset.d(66): Error: variable i cannot be read at compile time
/home/per/Work/justd/bitset.d(66):        while evaluating: static assert(i < 2LU)
/home/per/Work/justd/bitset.d(58): Error: bitset.BitSet!2.BitSet.opIndexAssign called with argument types (bool, int) matches both:
    /home/per/Work/justd/bitset.d(49): opIndexAssign(bool b, ulong i)

Должен ли я сделать параметр i параметром шаблона, скажем, используя тип U, а затем использовать статический, если someTypeTrait!U. Я пробовал это, но isMutable!Index всегда оценивается как true.

import std.traits: isIntegral;
bool opIndexAssign(Index)(bool b, Index i) @trusted pure nothrow if (isIntegral!Index) in {
    import std.traits: isMutable;
    // See also: http://stackoverflow.com/questions/19906516/static-parameter-function-specialization-in-d
    static if (isMutable!Index) {
        assert(i < len);
    } else {
        import std.conv: to;
        static assert(i < len,
                      "Index " ~ to!string(i) ~ " must be smaller than BitSet length " ~  to!string(len));
    }
} body {
    b ? bts(ptr, i) : btr(ptr, i);
    return b;
}

person Nordlöw    schedule 11.11.2013    source источник


Ответы (1)


То, что вы пытаетесь сделать, на самом деле не работает. Вы можете сделать параметр значения шаблона:

void foo(int i)() { /* use i at compile time */ }

но тогда вы не можете передать ему значение времени выполнения, и у него другой синтаксис вызова: foo!2 vs foo(2).

Самое близкое, что вы можете получить, это CTFE:

int foo(int i) { return i; }
enum something = foo(2); // works, evaluated at compile time
int s = foo(2); // also works, but runs at runtime.

Внутри функции есть волшебное if(__ctfe) { running at compile time } else { at runtime}, но опять же, это не если есть литерал, а если функция запускается в контексте CT, например, присваивая результат константе перечисления.

Но, в противном случае, литерал int по-прежнему является изменяемым int с точки зрения функции. Итак, то, что вы конкретно пытаетесь сделать, не будет работать в D, как сейчас. (Были разговоры о том, что нужно найти способ определить, является ли это литералом, но, насколько я знаю, на самом деле это не планируется.)

person Adam D. Ruppe    schedule 12.11.2013
comment
Ok. Я могу согласиться на индексацию, используя, например, bitset.at!3() на данный момент. Спасибо. - person Nordlöw; 12.11.2013