为什么std :: is_invocable不接受非类型模板参数

时间:2017-03-15 14:37:23

标签: c++ templates c++17 non-type

我最近偶然发现std::is_invocable将要引入C ++ 17标准,我想知道为什么它需要用户为函数指针提供类型而不是仅提供函数指针本身可能更方便,特别是因为非类型模板参数现在可以不受约束。

我的意思可以在下面的例子中解释

void hello_world() {
    cout << "Hello world" << endl;
}
int main() {
    cout << std::is_invocable_v<decltype(hello_world)> << endl;
    // as opposed to being able to do
    // cout << std::is_invocable_v<hello_world> << endl;

    return 0;
}

2 个答案:

答案 0 :(得分:5)

  

我想知道为什么它需要用户为函数指针提供一个类型而不是仅提供可能更方便的函数指针

因为始终拥有您要测试的可调用的类型,但您不总是拥有它作为一个常量表达式。当然,当你确实有价值时,你必须写出decltype(foo)而不仅仅是foo,但这似乎是一个相当小的负担,并且将覆盖相当大比例的用例。不确定是否值得增加template <auto F, class... Args> is_invocable的复杂性,以便有时候,用户不必写decltype

答案 1 :(得分:3)

std::is_invocable的主要用途是使用类型和模板参数。不仅可以直接使用函数指针。

让我们稍微改变你的代码并添加一个有用的案例:

void callF(F function, Args&& args) {
    std::invoke(function, std::forward<Args>(args)...);
}

// Later, in your main

callF(hello_world);

当调用调用无效时,您希望将函数过滤为不可调用。您可以像这样使用std::is_invokable

auto callF(F function, Args&& args) -> std::enable_if<std::is_invocable_v<F, Args...>> {
    std::invoke(function, std::forward<Args>(args)...);
}

如您所见,作为std::is_invocable的参数发送的类型反映了发送到std::invoke 的参数。

作为奖励,不仅仅支持函数指针。函数对象,甚至支持成员函数指针。现在,您可以使用callF函数:

callF([](int i){ /* ... */ }, 8);

struct Test { void test() {} };

Test t;

callF(&Test::test, t);