2

有没有办法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在这种情况下不能这样使用。我在问是否有办法实现这种行为(至少部分)。

4

1 回答 1

3

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

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

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

请注意,转换运算符仅被声明,未定义;所以这个结构可以decltype()std::declval()(and std::is_invocable) 一起使用,但不能被实例化。

现在您可以将higherOrderFunc传递引用写入passepartoutto 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; }

诀窍是,如果可调用对象等待auto(或auto &,或auto &&),则类型被推断为passepartout自身;当可调用等待特定类型(int在以下示例中,有或没有引用)时,模板operator T & ()(或operator T && ()根据情况而定)与预期类型兼容(在某种意义上)。

下面是一个完整的编译示例

#include <type_traits>
#include <iostream>

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

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

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; }

int main ()
 {
   auto l1a = [](auto &&){};
   auto l1b = [](int &){};
   auto l2a = [](auto &, int &&){};
   auto l2b = [](auto, int const &){};
   auto l2c = [](auto &&, auto const &){};
   auto l2d = [](int &&, auto const &, auto && ...){};

   higherOrderFunc(l1a);
   higherOrderFunc(l1b);
   higherOrderFunc(l2a);
   higherOrderFunc(l2b);
   higherOrderFunc(l2c);
   higherOrderFunc(l2c);
   higherOrderFunc(l2d);
 }
于 2019-07-06T11:55:23.290 回答