[英]Type deduction does not work with std::function
我有以下问题。 当我尝试编译以下代码时
template< typename T >
T func( T t)
{
return t;
}
template< size_t N, typename T >
void foo( std::function< T(T) > func )
{
// ...
}
int main()
{
foo<3>( func<float> );
return 0;
}
我得到错误:
no matching function for call to 'foo'
foo<3>( func<float> );
^~~~~~
/Users/arirasch/WWU/dev/xcode/tests/tests/main.cpp:18:10: note: candidate template ignored: could not match 'function<type-parameter-0-1 (type-parameter-0-1)>' against 'float (*)(float)'
void foo( std::function< T(T) > func )
但是,当我修复它
template< typename T >
T func( T t)
{
return t;
}
template< size_t N, typename T >
void foo( std::function< T(T) > func )
{
// ...
}
int main()
{
std::function< float(float) > input_func = func<float>;
foo<3>( input_func );
return 0;
}
即,当我将foo
的输入函数显式声明为std::function< float(float) >
,编译可以成功完成。
有谁知道我可以如何修正我的代码,以便我可以简单地编写诸如foo<3>( func<float> );
(根据我的第一个代码示例),而不是
std::function< float(float) > input_func = func<float>;
foo<3>( input_func );
在哪里必须明确声明input_func
的类型?
提前谢谢了。
这里的问题是,编译器必须执行重载解析才能找出哪些std::function<U(U)>
实例化具有可以采用T(*)(T)
构造函数。 就是说,可能有多种类型,每种类型可能都有多个input_func
,它们可能占用您的input_func
。
现在,如果看一下Standard,您会发现没有为std::function
指定这样的重载,但是所有模板的重载解决规则都是相同的,无论它们来自std::
, boost::
或ACME::
。 编译器不会开始实例化模板以查找转换序列。
提供完美匹配后,就无需转换顺序了。 恰好只有一种目标类型不需要转换序列,编译器会推断出这种类型。
在这种特殊情况下,您将了解函数指针与std::function
之间的关系,以及特定的限制,即您必须具有一个返回相同类型(没有T(*)(U)
)的单一函数,因此您可以增加过载
template< size_t N, typename T >
void foo(T(*func)(T))
{
return foo<N>(std::function<T(T)>(func));
}
类型推论在您的情况下不能正常工作,因为不能推导它。 在大多数情况下,类型推导是与类型和其他模板参数的简单匹配。 但是,C ++的某些暗角处理一些时髦的规则,但是我不会在此回答。
这是编译器可以推断模板参数的示例:
template<typename T>
void test(std::vector<T>);
test(std::vector<int>{1, 2, 3, 4, 5, 6});
这对于编译器来说很容易。 它需要T
的std::vector
。 您给它一个std::vector
int
。 T
必须是int
。
但是,在您的情况下,发生了很多事情:
template<typename T>
void test(std::function<T(T)>);
int someFunc(int);
test(someFunc);
编译器无法进行匹配。 自己尝试:给我一个T
,它将使这两种类型相等: int(*)(int)
到std::function<T(T)>
。 事实上,有没有可能T
,可以使这两个类型是相同的,而矢量版本是一个容易的比赛。
您会对我说:“但是……指向函数的指针可以转换为std :: function,这很愚蠢!” 是的,确实可以兑换。 但是在进行任何转换之前,编译器必须找到T
是什么。 如果没有T
,则将指针从函数转换为什么类? 很多班? 尝试匹配每个T
吗? 您的函数可以转换的可能性有多种。
你如何使这项工作? 忘记std::function
。 刚收到T
template<typename T>
T func(T t) {
return t;
}
template<size_t N, typename T>
void foo(T func) {
// ...
}
int main()
{
foo<3>( func<float> );
return 0;
}
注意此示例的工作方式。 您没有转换,没有std::function
麻烦,并且可以与您可以想象的任何可调用对象一起使用!
您是否担心接受任何类型? 不用担心! 参数类型是表达模板对接收到的参数仍然可以执行的操作的一种不好方法。 您应该使用表达式来限制它。 该表达式将告诉其他人您将如何使用T
以及T
需要具有什么接口。 顺便说一句,我们称这个sfinae:
template<size_t N, typename T>
auto foo(T func) -> decltype(void(func(std::declval<int>()))) {
// ...
}
在此示例中,将func
限制为可以使用int
调用的func
,并且仍然返回void
。
将func强制转换为std :: function可明确解决该问题。 例如,下面的代码有效。
template< typename T >
T func( T t)
{
return t;
}
template<typename T>
using FuncType = std::function<T(T)>;
template< size_t N, typename T >
void foo( FuncType<T> func )
{
// ...
}
int main()
{
func<float>(1.0);
foo<3>( FuncType<float>(func<float>) );
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.