2013-11-18 3 views
2

У меня есть шаблон функции, который принимает функцию в качестве аргумента. Я хотел бы получить имя аргумента функции из шаблона. Ниже приведен полный пример. См. Строку с надписью «COMPILE ERROR». Я попытался выполнить множество подобных действий, но я продолжаю получать ту же ошибку, «функция throws.thrower (int n) не может быть вызвана».Как получить имя псевдонима функции в шаблоне D?

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; 
} 
+1

Я хотел бы указать, что нет никакой гарантии, что 'fun' - это даже функция с именем. Это может быть функция лямбда или какой-либо другой вызываемый, который прошел. Кроме того, у нас есть 'std.exception.assertThrown', поэтому в стандартной библиотеке есть что-то, что делает то, что ваша функция пытается (хотя он использует файл и номер строки, а не имя функции в сообщении об ошибке). –

+0

Спасибо за подсказку - 'fullQualifiedName' дает« main .__ funcliteral1 », когда я тестирую его с помощью лямбда, что кажется достаточно разумным. Файл и строка, вероятно, более полезны. Я очень новичок в D, поэтому полезен указатель на 'assertThrown' в стандартной библиотеке. Я искал его в неправильных местах и ​​не понимал, что это было в этом модуле. По крайней мере, я изучил полдюжины новых вещей, изобретая это конкретное колесо :) – bstpierre

+0

Если вам не нужно полное имя и убедитесь, что он действительный символ, '__traits (identifier, Symbol)' тоже будет делать трюк. –

ответ

3

Вещь, которую я искал, - std.traits.fullyQualifiedName; изменение этой строки фиксирует ошибку компиляции и дает желаемый результат.

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 

который я ищу.

Смежные вопросы