我有以下问题。当我尝试编译以下代码时
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
的类型?
非常感谢提前。
答案 0 :(得分:4)
这里的问题是编译器必须执行重载解析以找出哪些std::function<U(U)>
实例具有可以采用T(*)(T)
的构造函数。也就是说,可能存在多种类型,每种类型可能有多个ctors可能会占用您的input_func
。
现在,如果您查看标准版,您会发现没有为std::function
指定此类重载,但所有模板的重载决策规则是相同的,无论它们来自{{1 },std::
或boost::
。编译器不会开始实例化模板以查找转换序列。
一旦提供完美匹配,就不需要转换序列。只有一种目标类型不需要转换序列,编译器推断出这种类型。
在这种特殊情况下,您了解函数指针与ACME::
之间的关系,以及您必须具有返回相同类型(无std::function
)的单一函数的特定限制,以便你可以添加一个重载
T(*)(U)
答案 1 :(得分:3)
类型扣除在您的情况下不起作用仅仅因为它无法推断。在大多数情况下,类型推导是与类型和其他模板参数的简单匹配。然而,有一些C ++的黑暗角落处理具有一些时髦规则的演绎,但我不会因为这个答案而进入演绎。
这是编译器可以推导出模板参数的示例:
template<typename T>
void test(std::vector<T>);
test(std::vector<int>{1, 2, 3, 4, 5, 6});
这对编译器来说很容易。它需要一个T的向量。你给它一个整数向量。 T必须是int。
然而,在你的情况下,还有很多事情发生了:
template<typename T>
void test(std::function<T(T)>);
int someFunc(int);
test(someFunc);
编译器无法进行匹配。亲自尝试:给我一个T
,使这两种类型相等:int(*)(int)
到std::function<T(T)>
。实际上,没有可能T
可以使这两种类型相同,而矢量版本很容易匹配。
你会对我说:&#34;但是...指向函数的指针可以转换成std :: function你傻了!&#34;是的,它确实是敞篷车。但在进行任何转换之前,编译器有来查找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) -> void_t<decltype(func(std::declval<int>()))> {
// ...
}
在此示例中,您可以使用func
限制int
可调用。
如果您还没有C ++ 17编译器,可以像这样实现void_t
:
template<typename...>
using void_t = void;
答案 2 :(得分:2)
将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;
}