C++ 可与任意函数参数类型一起使用

C++ 可与任意函数参数类型一起使用,c++,c++17,sfinae,type-deduction,invocable,C++,C++17,Sfinae,Type Deduction,Invocable,有没有一种方法可以对任意函数参数类型使用std::Is\u invocable,例如:std::Is\u invocable。其思想是检查函数是否可以接受1个参数,而不管参数的类型如何。对于一个用例,考虑两个lambdas: AutoLaBaDa1[](AutoX){ }} /代码>, AutoLaBaD2= [](AutoX,Auto y){}} /代码>,以及高阶模板函数: // specialize for 1 argument template<typename Function,

有没有一种方法可以对任意函数参数类型使用
std::Is\u invocable
,例如:
std::Is\u invocable
。其思想是检查
函数
是否可以接受1个参数,而不管参数的类型如何。对于一个用例,考虑两个lambdas:<代码> AutoLaBaDa1[](AutoX){ }} /代码>,<代码> AutoLaBaD2= [](AutoX,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);
//专门化1个参数
模板=真>
void higherOrderFunc(函数和函数);
//专门化两个参数
模板
void higherOrderFunc(函数和函数);
!std::is_invocable::value
在第一种情况下是为了防止重载函数的歧义(也就是说,在这种情况下,首选的专门化是2个参数,在歧义的情况下是1个参数)


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

也许不是一个完美的解决方案。。。但是你可以试试路路通的密码

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

   template <typename T>
   operator T && ();
 };
诀窍在于,如果一个可调用函数等待
auto
(或
auto&
,或
auto&
),则该类型被推断为
pass路通本身;当可调用函数等待特定类型时(
int
,在以下示例中有或没有引用),模板
运算符T&()
(或
运算符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);
 }
#包括
#包括
路路通大厦
{
模板
算子T&();
模板
算子T&();
};
模板
=正确>
虚高或虚高(F)

{std::cout似乎没有任何方法可以检查这一点。为什么需要检查?恐怕这是不可能的,因为它需要将所有类型替换到函数模板中。您可以使用只对模板参数的某些组合有效的函数模板,并且这些条件可以任意复杂。请注意,只有函数可以调用,而不是模板。这可能是一个什么样的用例?最后,你仍然想使用一些具体的类型,那么,为什么不检查它们呢?@Quimby假设你有100个类型,手动编写所有这些类型的检查是不实际的。整个事情都与实现更高阶的函数有关。不确定如何为了帮助你,可调用性可能取决于它的参数。即使是<代码>模板FO(t,t)< /> >对于所有类型的两个参数都是无效的。并且模板没有限制。函数本身可能被重载,所以C++只能回答“如果我把这些具体的参数放在那里,是<代码> FUNC(ARGS…)< /COD>有效表达式?”类和函数模板都是在实例化的情况下用具体类型来检查的,因此编译器可以针对这些具体类型开始匹配可用模板。您的要求是相反的。您可以给出一个更具体的例子,其中高阶函数用于某些东西?不必是可编译的C++。ile这确实是一个局部解决方案,它与florestan的
任意类型(
)存在相同的问题,其中它需要lambda内部的强制转换。例如,尝试
auto l2a=[](auto x,auto y){return x+y;};
@lightxbulb-是的…仅对
decltype()
类似用途有用(as
std::is invocable
)和(我想)期待更多的东西是不合理的。@lightxbulb-删除操作符实现可能有意义:
decltype()
std::is_invocable
继续工作,直接使用
passspartout
的诱惑减少了。但仍然存在
自动和
问题。@lightxbulb-我修改了答案,删除了转换运算符定义并将引用传递到
std::is invocable
;这非常简单确认答案,并且应该解决
自动&
问题。感谢您这么做。虽然它不直接适用于我的用例(因为我实际上不想强制转换lambdas)这是一个部分的解决方案,所以我将接受它作为答案,考虑到C++目前似乎没有提供一个机制来实现我想要的。希望在未来的标准迭代中,在某个时候,甚至可以查询特定函数的所有重载的类型和类型。(例如,作为元组的静态数组返回)。
#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);
 }