Адрес функции шаблона С++
Почему это не удается скомпилировать? (g++ - 4.5)
template < typename U >
static void h () {
}
int main () {
auto p = &h<int>; // error: p has incomplete type
}
РЕДАКТИРОВАТЬ: Вот работа:
template < typename U >
static void h () {
}
int main () {
typedef decltype (&h<int>) D;
D p = &h<int>; // works
}
Ответы
Ответ 1
В С++ 0x это гарантировано. Однако в С++ 03 это не работало (часть инициализатора, то есть), а некоторые компиляторы, по-видимому, еще не поддерживают его.
Кроме того, я помню, что формулировка С++ 0x не ясна, что происходит с &h<int>
, когда она является аргументом шаблона функции и выведен соответствующий параметр (это то, что auto
переводится, концептуально). Однако намерение состоит в том, что оно действительно. См. этот отчет о дефектах, где они разработали формулировку, пример "Нико Йосуттис" и их последний пример.
Существует другое правило, которое формулирует, но компиляторы неправильно реализуют. Например, см. Этот clang PR.
Ответ 2
Он не компилируется, потому что тип 'p' не известен компилятору, который является обязательным в С++, в отличие от некоторых других языков.
Try
template < typename U >
static void h () {
}
int main () {
auto void (*p)() = &h<int>;
}
Ответ 3
Try
auto p = static_cast<void(*)()>(& h<int>);
Потому что gcc рассматривает шаблонную функцию как перегруженную. С точки зрения gcc это похоже на то, что у вас есть h(int param)
и h(float param)
- какой компилятор должен выбрать?
Я заметил, что было проблемой в более старых версиях gcc, но я попытаюсь объяснить это более подробно. GCC не смог вывести тип, потому что шаблонная функция обрабатывалась как перегруженная. Это было похоже на то, что у вас будет следующее:
void h(int)
{
}
void h(float)
{
}
void (*p)(int) = & h; //ok
void (*p)(float) = & h; //ok
auto p = & h; //error: which version of h?
Для gcc h<int>
была похожа на перегруженную функцию h
с бесконечными альтернативами в зависимости от параметра T
. С кодом, о котором идет речь, был O.K. для выполнения следующих действий:
void (*p)() = & h<int>;
(вот почему я не набираю "обход" )
Поскольку я думал, что OP хочет использовать ключевое слово С++ 11 auto
, как было предложено тегом, я статически выбрал h<int>
to void(*)()
, который вроде бы не работает, просто для трюка gcc, потому что он не имел возможности правильно обрабатывать шаблонные функции и auto
.
Функции void h<int>()
и void h<float>()
должны, конечно, рассматриваться как разные функции с одним и тем же типом указателя, а не с перегрузкой версий функции h
. При создании экземпляра они должны вести себя как void hInt()
и void hFloat()
, и вы должны иметь возможность использовать auto, как здесь:
void hInt()
{
}
void hFloat()
{
}
auto p = hInt;
p = hFloat;
Но почему-то для gcc они были похожи на перегруженные версии h
.
Просьба указать причину падения.