类型演绎不适用于std::function
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
的类型?
提前感谢。
类型演绎在您的情况下不起作用,因为它不能被演绎。在大多数情况下,类型推导是与类型和其他模板参数的简单匹配。然而,c++中有一些黑暗的角落处理演绎,有一些奇怪的规则,但我不会在这个答案中深入探讨。
这是一个编译器可以推断模板参数的例子:
template<typename T>
void test(std::vector<T>);
test(std::vector<int>{1, 2, 3, 4, 5, 6});
这对编译器来说很容易。它需要T
的std::vector
。你给它一个int
的std::vector
。T
必须是int
然而,在你的情况下,有很多事情正在发生:
template<typename T>
void test(std::function<T(T)>);
int someFunc(int);
test(someFunc);
编译器无法进行匹配。自己试一下:给我一个T
,使这两种类型相等:int(*)(int)
到std::function<T(T)>
。实际上,不可能存在使这两种类型相同的T
,而vector版本则很容易匹配。
你会对我说:"但是……指向函数的指针可以转换为std::函数,你这个傻瓜!"是的,它的确是敞篷的。但是在任何转换之前,编译器必须查找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
,并且仍然返回void
。
这里的问题是编译器必须做重载解析,以找出哪些std::function<U(U)>
实例化具有可以接受T(*)(T)
的构造函数。也就是说,可能有多种类型,每种类型都可能有多个可以获取input_func
的因子。
现在,如果你看一下标准,你会发现没有为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));
}
将function转换为std::函数显式地解决了这个问题。例如,下面的代码可以工作:
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;
}
- 库函数需要一个 std::function<void(void)>,如何传入类函数?
- Confusion: decltype vs std::function
- 为什么 std::function 可以作为 std::not2 的参数?
- 'max'匹配'std::function<const int &(const int &, const int &)>'无过载
- 传递给std::function template的template参数究竟代表什么
- 将带有unique_ptr的可变 lambda 传递给 const&std::function
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 如何在向量中删除 std::function<void()>?
- 将函数包装器转换为 std::function
- 类型擦除的std::function与虚拟函数调用的开销
- C++ std::function 对于类 exept 的所有实例都是空的(只有 Visual2019 编译器问题)
- 如果模板没有可变参数,则 Lambda 被推导出为 std::function
- 将 lambda 表达式传递给 std::function in C++
- 广义 std::function (std::any 表示可调用对象)
- std::function<std::optional<T>()> 如何与返回 T 的 lambda 兼容?
- std::function std::bind with lambda overload ambiguity
- Clang bug with std::function, std::bind and std::ref?
- 为什么我会收到编译错误"use of deleted function 'std::unique_ptr ..."
- 为什么我不能让 std::function<std::vector<T>::iterator> 绑定到返回该类型的 lambda?
- 回调(std::function/std::bind)与接口(抽象类)的优缺点