C++ 修改后的std::invoke/std::apply,将可调用对象视为空*-可能吗?
在C++17中,我们有C++ 修改后的std::invoke/std::apply,将可调用对象视为空*-可能吗?,c++,c++11,higher-order-functions,c++-standard-library,c++17,C++,C++11,Higher Order Functions,C++ Standard Library,C++17,在C++17中,我们有std::invoke: template<class F, class... ArgTypes> std::result_of_t<F&&(ArgTypes&&...)> invoke(F&& f, ArgTypes&&... args); 与std::invoke的区别在于f是通过一个空指针传递的,其类型没有模板参数。但是,如果f是指向普通独立函数的指针,则人类读者可以推断出该类型
std::invoke
:
template<class F, class... ArgTypes>
std::result_of_t<F&&(ArgTypes&&...)> invoke(F&& f, ArgTypes&&... args);
与std::invoke
的区别在于f是通过一个空指针传递的,其类型没有模板参数。但是,如果f
是指向普通独立函数的指针,则人类读者可以推断出该类型,我可以这样做:
template<typename T, typename... ArgTypes>
T my_invoke(void* f, ArgTypes&&... args)
{
using type_unerased_function = T (*)(ArgTypes...);
return reinterpret_cast<type_unerased_function>(f)(args...);
}
模板
T my_invoke(void*f,ArgTypes&&…args)
{
使用type_unerased_function=T(*)(ArgTypes…);
返回重新解释(f)(参数…);
}
这似乎有效。但是,std::invoke
支持成员函数、带有operator()
的对象,可能还支持其他标准(并且std::apply
也支持比普通函数指针更多的东西)。上述功能是否可以扩展以支持std::invoked
的大部分/全部功能
注意事项:
- 我从签名中删除了constexpr,因为我愿意放弃它。如果能以某种方式保存constexpr,那就太好了
- 我可能把这里的转发搞砸了
void f(short);
可以使用0
调用,但是0
被推断为类型int&
,并且您的代码将void指针强制转换为void(*)(int)
。这些类型不兼容
如果你取intzero=0
然后将zero
传递给你的怪物,你推断出void指针为void(*)(int&)
。虽然第一个可能会基于堆栈对齐(go go undefined behavior)意外地工作,但这一个会立即segfault(这至少会让您注意到错误,而不是错过它并在以后感到困惑)
期望调用给定函数的参数类型不足以确定调用对象的类型。即使是这样,它也是脆弱和危险的,一声咕噜就会让你抓狂
现在,你想把它扩展到一堆其他东西。每一个都有不同的布局和调用约定。成员函数指针的大小可能不同,并且不能保证它们适合空*
,更不用说可以像函数一样处理了
现在是好消息。你的问题是你在错误的地方擦除。当你拥有你需要的信息时,你需要删除它,在你扔掉它后不久 您确实需要知道希望向这个已擦除的对象提供什么类型的参数 假设您知道它将被类型
arg1、arg2、arg3
调用。然后我们可以将其存储在:
std::function<void(arg1, arg2, arg3)>
std::函数
所以现在你要:
std::function<void(arg1,arg2,arg3)> f = my_invokable;
std::function f=my_可调用;
而std::function
将执行std::invoke
步骤来处理函数指针、()
重载的对象和成员函数指针(其中第一个参数现在是this
)
很可能这个问题实际上是为了解决脚本接口生成之类的问题。像大多数这样的问题一样,有人试图解决它,说“如果我能解决这个子问题,我就会完成”,然后询问子问题,但不包括激励上下文。请减少您的问题,如上述,但始终包括激励上下文
您的问题可能可以通过在不同的位置进行类型擦除来解决。当然,如果不首先删除信息,“我删除了有关对象类型的所有信息。我如何知道对象的类型?”。我很难想象你在想什么,写这个问题;我想不出对这个问题的任何解释来提供一个有用的答案。有点,但除非我完全误解了你的问题,否则你的要求是不可能的,因为你几乎把它设定为不可能。这不是一个有用的答案。(一般来说,BTW,参数类型即使对于函数指针也是不够的。考虑调用<代码>空格F(long)<代码>,使用类型<代码> int 。)HVD:实际上这是一个有用的答案,从某种意义上说,这是我想知道的——如果是这样的话。但是“我不知道怎么做”和“我肯定做不到”是两个不同的答案,只有第二个答案是有用的。对于
void foo(std::string,const std::string&)
,my_invoke(&foo,“string”s,“string”s),
将使用void(*)(std::string,std::string)
,甚至最糟糕的是my_invoke(&foo,“ptr”,“ptr”)
将使用void(*)(const char(&)[4],const char(&)[4])
通常,试图从稍后传递的参数的类型和值类别中推断可调用的签名来调用它是一个可怕的想法。当您无法检查推断的结果是否正确时,更是如此。
std::function<void(arg1,arg2,arg3)> f = my_invokable;