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()
类似用途有用(asstd::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);
}