Следующий код, построенный с помощью
clang -Wall main.cpp -o main.o
генерирует следующую диагностику (после кода):
template <typename F>
void fun(const F& f)
{
}
template <typename F>
void fun(F f)
{
}
double Test(double d) { return d; }
int main(int argc, const char * argv[])
{
fun(Test);
return 0;
}
Диагностика:
main.cpp:17:5: error: call to 'fun' is ambiguous
fun(Test);
^~~
main.cpp:2:6: note: candidate function [with F = double (double)]
void fun(const F& f)
^
main.cpp:8:6: note: candidate function [with F = double (*)(double)]
void fun(F f)
^
1 error generated.
Интересная часть заключается не в самой ошибке двусмысленности (что не является главной проблемой здесь). Интересная часть состоит в том, что параметр шаблона F
первого fun
разрешен как чистый тип функции double (double)
, тогда как параметр шаблона F
второго fun
разрешен как более ожидаемый double (*)(double)
тип указателя функции, когда fun вызывается только с именем функции.
Однако, когда мы меняем вызов fun(Test)
на fun(&Test)
, чтобы явно использовать адрес функции (или явный указатель функции), то оба fun
разрешают параметр шаблона F
равным double (*)(double)
!
Такое поведение, по-видимому, является общим для всех Clang и GCC (и Visual Studio 2013).
Возникает вопрос: каково правило вывода параметра шаблона шаблона для функций шаблона в формах, приведенных в моем примере кода?
PS: если мы добавим еще один экземпляр fun
, чтобы взять F* f
, то, похоже, правило перегрузки просто решает выбрать эту версию, и никакой двусмысленности вообще не сообщается (хотя, как я уже сказал, двусмысленность не является самой большой проблемой ранее, но в этом последнем случае я действительно удивляюсь, почему третья версия здесь лучше всего подходит?)
template <typename F>
void fun(F* f)
{
}