【问题标题】:`std::enable_if` is function pointer - how?`std::enable_if` 是函数指针 - 如何?
【发布时间】:2013-09-11 01:15:20
【问题描述】:

如果用户将 函数指针 作为参数传递,我想使用 SFINAE 来启用特定模板。

我在 Google 上四处搜索,但一无所获 - 我还尝试查看 <type_traits> 文档,但找不到类似于 is_function_ptr<T> 的任何内容。

函数指针是指全局函数指针,例如TReturn(*)(TArgs...)。

【问题讨论】:

  • 你能同时检查 is_function 和 is_pointer 吗?
  • 为什么选择 SFINAE?这里有点矫枉过正。
  • 为什么没有简单的 f(std::function) ?
  • @n.m.,Dieter Lücking:我需要在编译时区分成员函数指针、函数指针和仿函数。
  • @NicolasLouisGuillemot:我找不到将两者结合起来的正确方法——我认为is_function 不适合检查函数指针(不过我可能错了)。

标签: c++ templates pointers c++11 enable-if


【解决方案1】:

下面是一个类型特征,用于确定某个东西是否是函数指针和几个测试用例。请注意,要测试某物是否是函数指针,您需要测试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){});
}

【讨论】:

  • 你可以很容易地从constexpr函数模板和nm的答案中创建一个特征,不是吗?而且它会更强大(您可能需要最少数量的参数或特定的返回类型)。
  • @BenVoigt:当然。但是,问题不是“如何根据 nm 的解决方案检测某个东西是否是函数指针”,也不是关于最小参数数量或特定返回类型的问题。
  • 是的,但enable_if 并不关心该特征是完全由remove_pointer 构建的还是直接实现的。
  • 这帮助我解决了我的this question,谢谢,+1。
【解决方案2】:

不需要 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());
}

【讨论】:

    猜你喜欢
    • 2012-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    • 2020-05-30
    • 1970-01-01
    • 2015-03-09
    相关资源
    最近更新 更多