Я хочу использовать SFINAE для включения определенного шаблона, если пользователь передает указатель на функцию в качестве параметра.
Я погуглил, но ничего не нашел — я тоже попытался посмотреть на <type_traits>
документация, но не смог найти ничего похожего на is_function_ptr<T>
,
Под указателем на функцию я имею в виду глобальные указатели на функции, например TReturn(*)(TArgs...)
,
Ниже приведена характеристика типа, определяющая, является ли объект указателем на функцию и парой тестовых случаев. Обратите внимание, что для проверки, является ли что-то указателем на функцию, необходимо проверить, std::is_pointer<P>::value
является true
и если std::is_function<T>::value
является true
где T
является P
с удаленным указателем. Код ниже просто делает это:
#include <type_traits>
#include <iostream>
#include <utility>
template <typename Fun>
struct is_fun_ptr
: std::integral_constant<bool, std::is_pointer<Fun>::value
&& std::is_function<
typename std::remove_pointer<Fun>::type
>::value>
{
};
template <typename Fun>
typename std::enable_if<is_fun_ptr<Fun>::value>::type
test(Fun) {
std::cout << "is a function pointer\n";
}
template <typename Fun>
typename std::enable_if<!is_fun_ptr<Fun>::value>::type
test(Fun) {
std::cout << "is not a function pointer\n";
}
void f0() {}
void f1(int) {}
void f2(int, double) {}
struct s0 { void operator()() {} };
struct s1 { void operator()(int) {} };
struct s2 { void operator()(int, double) {} };
int main()
{
int v0(0);
int* p0(&v0);
void (*p1)() = &f0;
void (**p2)() = &p1;
std::cout << "v0="; test(v0);
std::cout << "p0="; test(p0);
std::cout << "p1="; test(p1);
std::cout << "p2="; test(p2);
std::cout << "f0="; test(&f0);
std::cout << "f1="; test(&f1);
std::cout << "f2="; test(&f2);
std::cout << "s0="; test(s0());
std::cout << "s1="; test(s1());
std::cout << "s2="; test(s2());
std::cout << "l0="; test([](){});
std::cout << "l1="; test([](int){});
std::cout << "l2="; test([](int, double){});
}
SFINAE не требуется для принятия указателя на функцию или указателя на функцию-член. Чтобы отличить функциональные объекты от не подлежащих вызову вещей, необходим SFINAE, вероятно, нет никакого способа обойти это.
#include <utility>
#include <iostream>
template <typename Ret, typename... Parm>
void moo (Ret (*fp)(Parm...))
{
std::cout << "funptr" << std::endl;
}
template <typename Ret, typename Owner, typename... Parm>
void moo (Ret (Owner::*fp1)(Parm...))
{
std::cout << "memfunptr" << std::endl;
}
template <typename Funobj, typename... Parm,
typename Ret =
decltype((std::declval<Funobj>())
(std::forward(std::declval<Parm>())...))>
void moo (Funobj functor)
{
std::cout << "funobj" << std::endl;
}
void x1() {}
struct X2 { void x2() {} };
struct X3 { void operator()(){} };int main()
{
moo(x1);
moo(&X2::x2);
moo(X3());
}