Как получить имя псевдонима функции в шаблоне D?

У меня есть шаблон функции, который принимает функцию в качестве аргумента. Я хотел бы иметь возможность получить имя аргумента функции из шаблона. Полный пример ниже. См. строку с пометкой «ОШИБКА КОМПИЛЯЦИИ» — я пытался сделать множество вещей, подобных этому, но все равно получаю ту же ошибку: «Функция throws.thrower (int n) не вызывается».

import std.array;
import std.conv;
import std.format;
import std.stdio;

int thrower(int n)
{
    if(n > 5)
        throw new core.exception.RangeError("too big");
    return n * 2;
}

int thrower2(int x, int y)
{
    int product = x * y;
    if(product > 25)
        throw new core.exception.RangeError("too big");
    return product;
}

void assertThrows(alias fun, E, T...)(T t)
{
    try
    {
        fun(t);

        auto writer = appender!string();
        formattedWrite(writer,
                       "Expected %s to throw %s, but it did not",
// throws.d(32): Error: function throws.thrower (int n) is not callable using argument types ()

                       //fun.stringof, // <<-- COMPILE ERROR
                       "?",
                       E.stringof);

        throw new core.exception.AssertError(writer.data);
    }
    catch(E ex)
    {
        // Success - we got the expected exception - do nothing.
    }
    // We don't catch any other exceptions -- if these occur they will
    // cause a failure directly, or be handled by other test code that
    // may be expecting the exception. Either way we don't want to
    // interfere.
}

int main()
{
    assert(thrower(5) == 10);
    assertThrows!(thrower, core.exception.RangeError)(6);
    assertThrows!(thrower2, core.exception.RangeError)(9, 9);
    assertThrows!(thrower2, core.exception.RangeError)(1, 1); // Should fail

    return 0;
}

person bstpierre    schedule 18.11.2013    source источник
comment
Я хотел бы отметить, что нет никакой гарантии, что fun является даже функцией с именем. Это может быть лямбда-функция или какая-то другая вызываемая функция, которая была передана. Кроме того, у нас есть std.exception.assertThrown, так что в стандартной библиотеке уже есть что-то, что делает то, что пытается сделать ваша функция (хотя она использует файл и номер строки, а не функцию имя в сообщении об ошибке).   -  person Jonathan M Davis    schedule 18.11.2013
comment
Спасибо за совет - fullyQualifiedName дает main.__funcliteral1, когда я тестирую его с лямбдой, что кажется достаточно разумным. Файл и строка, вероятно, более полезны. Я очень новичок в D, поэтому указатель на assertThrown в стандартной библиотеке полезен. Я искал его не в тех местах и ​​не знал, что он находится в этом модуле. По крайней мере, я узнал полдюжины новых вещей, заново изобретая это конкретное колесо :)   -  person bstpierre    schedule 18.11.2013
comment
Если вам не нужно полное имя и вы уверены, что это допустимый символ, __traits(identifier, Symbol) тоже подойдет.   -  person Mihails Strasuns    schedule 19.11.2013


Ответы (1)


Я искал std.traits.fullQualifiedName; изменение этой строки исправляет ошибку компиляции и дает желаемый результат.

    formattedWrite(writer,
                   "Expected %s to throw %s, but it did not",
                   fullyQualifiedName!fun,
                   E.stringof);

Это дает вывод для программы в вопросе:

[email protected](37): Expected throws.thrower2 to throw RangeError, but it did not

это то, что я ищу.

person bstpierre    schedule 18.11.2013