is_invocable具有任意函数参数类型

时间:2019-07-06 10:34:54

标签: c++ c++17 sfinae type-deduction invocable

是否可以将std::is_invocable与任意函数参数类型一起使用,例如:std::is_invocable<Function, auto>。这个想法是检查Function是否可以接受1个参数,而不管参数的类型如何。对于一个用例,请考虑两个lambda:auto lambda1 = [](auto x) {...}auto lambda2 = [](auto x, auto y) {...}和一个更高阶的模板化函数:

// specialize for 1 argument
template<typename Function, std::enable_if_t<(std::is_invocable<Function, auto>::value && !std::is_invocable<Function, auto, auto>::value)>, bool> = true>
void higherOrderFunc(Function&& func);

// specialize for 2 arguments
template<typename Function, std::enable_if_t<std::is_invocable<Function, auto, auto>::value, bool> = true>
void higherOrderFunc(Function&& func);

第一种情况下的!std::is_invocable<Function, auto, auto>::value是为了防止重载函数产生歧义(也就是说,在这种情况下,首选的专业化将是歧义的2个参数)。

请注意,我知道在这种情况下不能像这样使用auto。我在问是否有办法(至少部分地)实现这种行为。

1 个答案:

答案 0 :(得分:2)

也许不是一个完美的解决方案...但是您可以尝试使用passepartout

struct passepartout
 {
   template <typename T>
   operator T & ();

   template <typename T>
   operator T && ();
 };

观察到仅​​声明转换运算符,未定义;因此该结构可以在decltype()std::declval()(以及std::is_invocable)中使用,但无法实例化。

现在,您可以将higherOrderFunc的{​​{1}}传递引用写入passepartout

std::is_invocable

诀窍在于,如果可调用对象等待template <typename F, std::enable_if_t< std::is_invocable_v<F, passepartout &> && ! std::is_invocable_v<F, passepartout &, passepartout &>, bool> = true> void higherOrderFunc (F) { std::cout << "-- one parameter callable" << std::endl; } template <typename F, std::enable_if_t< std::is_invocable_v<F, passepartout &, passepartout &>, bool> = true> void higherOrderFunc (F) { std::cout << "-- two parameter callable" << std::endl; } (或autoauto &),则类型推导为auto &&本身;当可调用等待特定类型(在以下示例中为passepartout,带有或不带有引用)时,模板int(根据情况为operator T & ())在某种意义上是兼容的)与预期的类型。

以下是完整的编译示例

operator T && ()