C 从函数指针推导的转发参数时无隐式转换
C++ no implicit conversions when forwarding arguments deduced from function pointer
我正在尝试产生一个智能的代理函数,以便将参数转发为给定。
这是代码:
#include <utility>
#include <iostream>
void func(int foo) {
std::cout<<foo<<"n";
}
template<typename... ARGS>
void proxy( void(*callback)(ARGS...), ARGS&&... args) {
callback( std::forward<ARGS>(args)... );
}
int main() {
proxy( func, 17 );
int foo = 17;
proxy( func, foo );
}
我希望通过让模板分辨率找出func
的参数,我将获得签名void proxy( void(*)(int), int );
的代理。因此,它应该同时接受第一个调用(int是rvalue(或第二个(int是lvalue(。
实际上,上述程序失败了:
so.cpp:16:5: error: no matching function for call to 'proxy'
proxy( func, foo );
^~~~~
so.cpp:9:6: note: candidate template ignored: deduced conflicting types for parameter 'ARGS' (<int> vs. <int &>)
void proxy( void(*callback)(ARGS...), ARGS&&... args) {
^
1 error generated.
即。 - 未能隐式从int &
转换为int
。
我在这里做错了什么?
问题是有两个地方可以从中推断出ARGS
。函数模板参数扣除始终是针对每个函数参数/参数对进行的,然后组合的。
[temp.deduct.type]
2在某些情况下,扣除是使用一组 类型
P
和A
,在其他情况下,将有一组 相应类型P
和A
。类型扣除是独立完成的 对于每个P
/A
对,而推论的模板参数值为 然后组合。如果对任何P
/A
对都无法进行类型扣除,则 或者,对于任何一对,扣除会导致多组 推导值的定推值,或者如果不同的对产生不同的推导 值,或任何模板参数既不推导,也没有 明确指定的模板参数扣除失败。一种类型 type参数仅是从数组绑定中推导的 否则推导。
由于函数参数包包含转发引用,因此它将根据相应参数的值类别推导int&
或int
。虽然功能类型(也发生扣除(只能导致int
的扣除。对于LVALUES,这两种扣除额不同意,因此替代失败了。
未能替代不是错误,它只是从候选人集中删除过载。但是就您而言,这是唯一的候选人,因此变成了困难。
因此,您需要使两种扣除独立,这意味着两个包装。这仍然会给我们int&
与int
,但是我们可以添加SFIANE检查,以验证删除参考后的类型。这应该给出所需的行为。
template<typename... ARGS1, typename... ARGS2>
std::enable_if_t<(std::is_same_v<std::decay_t<ARGS1>, std::decay_t<ARGS2>> && ...)>
proxy( void(*callback)(ARGS1...), ARGS2&&... args) {
callback( std::forward<ARGS2>(args)... );
}
返回类型使用折叠表达式来验证每对参数,但只有在删除了其CV- Qualifiers和参考类型之后(这就是decay_t
的目的,除其他方面(。如果支票通过,则存在enable_if_t
,并且是void
(enable_if
的默认::type
(。
这里是现场。
但是,如果您决定要支持可转换性,则可以修改上述检查以使用std::is_convertible_v
而不是std::is_same_v
。
不幸的是,Args模板参数的两个位置允许每个变量扩展(以及每个单独的参数(不同类型。
您需要提出参数(例如,args&amp;&amp; ... args(依赖或静态演员。您可以执行一种乏味的方法,我认为它保留了完美的转发,这是最后显示的,因为它漂亮的冗长。
这种方法是我的最爱,因为它在intelisense中表现出色。在某些情况下,这种方法不是"完美的",但是它几乎总是一样,所以也许对您有好处:(:
#include <iostream>
using namespace std;
void func (int foo)
{
std::cout << foo << "n";
}
template <typename T>
struct Mirror
{
using type = T;
};
template < typename ... FunctionArgs >
void proxy (void (*callback) (FunctionArgs ...), typename Mirror<FunctionArgs>::type ... args)
{
callback (args ...);
}
int main ()
{
proxy (func, 17);
int foo = 17;
proxy (func, foo);
}
静态铸造方法:
#include <iostream>
using namespace std;
void func (int foo)
{
std::cout << foo << "n";
}
template < typename ... FunctionArgs, typename ... UsedArgs >
void proxy (void (*callback) (FunctionArgs ...), UsedArgs && ... args)
{
callback (static_cast < FunctionArgs > (args) ...);
}
int main ()
{
proxy (func, 17);
int foo = 17;
proxy (func, foo);
}
冗长的方法,我认为这保留了所有完美的转发:
#include <iostream>
using namespace std;
void func (int foo)
{
std::cout << foo << "n";
}
template <typename T>
struct Mirror
{
using type = T;
};
template < typename ... FunctionArgs, typename ... UsedArgs >
void proxy (void (*callback) (FunctionArgs ...), UsedArgs && ... args)
{
callback ([](auto m, auto && a) -> decltype(auto)
{
if constexpr (std::is_reference_v<decltype(a)>)
{
return std::forward<decltype(a)>(a);
}
else
{
return static_cast<typename decltype(m)::type>(a);
}
}( Mirror<UsedArgs>{}, std::forward<FunctionArgs>(args) ) ... );
}
int main ()
{
proxy (func, 17);
int foo = 17;
proxy (func, foo);
}
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何将向量中的可变参数转换为参数的持有者?
- c++ 构造函数 将 1 个字符串参数转换为 3 个属性
- 将空*参数转换为各种类型的参数是UB吗?
- 将可变参数模板参数转换为 JSON 字符串
- C++ 如何将函数参数转换为字符串
- 功能指针参数参数转换为const
- 避免对模板运算符过载的隐式参数转换
- 将C 方法参数转换为模板参数会因编译错误而失败
- 将参数转换为lpwstr createProcess
- 在与时间一起使用 srand 时,如果我没有time_t参数明确地将参数转换为无符号的 int 参数,这有关系吗?
- 将C++整型模板参数转换为整型"longer"型
- 将参数转换为目标类型时,复制用于直接初始化的构造函数省略
- 将命令行参数转换为qimage
- 将可变数量的参数转换为明确的数量
- SDL 方法,参数转换
- 通过错误检查将参数转换为整数
- 功能参数转换为儿童类C
- 参数转换在课堂上
- 在窗口上将格式化的 C 字符串和参数转换为 wstring