为什么在传递lambda而不是功能指针时不能推断模板参数
Why could not deduce template argument when passing lambda instead of function pointer
i具有一个泡泡函数,该功能采用数组,比较函数和一个布尔值,该功能指示是否应颠倒地对数组进行分类。这是一个支持任何数据类型的模板函数,并将自动推断数组大小。
指定比较函数时,如果我通过功能指针,编译器将自动推导数组的数据类型,这很棒。但是,如果我通过lambda,它不会自动推导。我必须明确指定数据类型,或static_cast
lambda为fnCompare_t<double>
。
背后的原因是什么?因为根据这篇文章,只要lambda没有捕获,它就可以像纯老功能指针一样使用,但似乎并非总是如此?在这种情况下怎么会有所不同?
#include <iostream>
using namespace std;
template <typename T>
using fnCompare_t = int(*)(T const &, T const &);
template <typename T, size_t count>
inline void BubbleSort(
T(&array)[count],
fnCompare_t<T> fnCompare,
bool reverse)
{
cout << "TODO: Implement BubbleSort" << endl;
}
double doubleArray[] = {
22.3, 11.2, 33.21, 44.2, 91.2, 15.2, 77.1, 8.2
};
int CompareDouble(double const & a, double const & b)
{
return a > b ? 1 : a == b ? 0 : -1;
}
int main()
{
auto fnCompare = [](double const & a, double const & b) -> int {
return a > b ? 1 : a < b ? -1 : 0;
};
// compile OK:
BubbleSort(doubleArray, CompareDouble, false);
BubbleSort(doubleArray, static_cast<fnCompare_t<double>>(fnCompare), false);
BubbleSort<double>(doubleArray, fnCompare, false);
// compile error, could not deduce template argument:
//BubbleSort(doubleArray, fnCompare, false);
return 0;
}
的原因是因为使用扣除时,您无法对模板参数进行隐式转换。经典的例子是:
template <class T>
T min(T x, T y);
将此功能称为min(1, 3.0)
将导致故障。因为对于这两个参数,它都试图找到T
以获得完美的匹配和失败。如果明确指定模板参数可以工作:min<double>(1, 3.0)
。在您的示例中,情况也是如此,如果您明确指定T
,它将起作用。
编写功能签名的惯用方式是:
template <typename Iter, typename F>
inline void BubbleSort(
Iter b, Iter e,
F fnCompare,
bool reverse)
但是,这会丢弃编译时长度信息。如果要保留它,可以做:
template <typename T, size_t count, typename F>
inline void BubbleSort(
T(&array)[count],
F fnCompare,
bool reverse);
尽管您至少应该考虑使用std::array
而不是C样式数组,这会使签名少一些丑陋,并且具有其他好处。
这似乎很奇怪,因为我们没有按照我们的签名"验证"具有正确签名的比较器。但这在C 中是正常的,如果比较器不正确,则在使用时会失败,并且仍然是编译时间错误。还要注意,当您尝试依靠lambda隐式转换为函数指针时,您是不必要的限制性的:lambdas仅通过相同的签名将功能指针转换为函数指针。即使Lambda的输出可隐式转换为功能指针的输出,即使Lambda仍然可以使用!
,您的lambda也不会隐式转换!作为最后的说明,通常最好通过函子,因为它对性能更好。比较器通常是很小的功能,通常会被内衬。但是在您的版本中,比较器通常不会夹住,在我的版本中,它将(因为我保留了lambda的原始类型,而您却没有(。
您需要将lambda明确施放到功能指针上。没有其他方法可以解决。但是,您可以将+
应用于lambda,而不是static_cast
,这将触发功能指针转换,因为您可以将+
应用于指针类型:
BubbleSort(doubleArray, +fnCompare, false);
// ^^
// applying unary + invokes the function pointer conversion operator
为什么没有隐含呼吁转换操作员的原因是,在超载分辨率期间,编译器只会考虑完美匹配的模板(有关更多信息,请参见此信息(。由于lambda不是功能指针,因此不能有完美的匹配,并且超载被丢弃。
- C++ 中的线程不能使用参数
- 为什么我们不能重复使用具有不同模板参数的别名模板标识符?
- 为什么我不能将引用作为 std::async 的函数参数传递
- Clang-Format 不能正确分配函数参数
- 为什么带有指针子对象的文字类类型的 constexpr 表达式不能是非类型模板参数
- 可变参数函数模板不能很好地使用 std::function 作为参数
- 为什么我不能用两个参数重载 C++ 运算符 []?
- 为什么std::{container}::template不能推导其参数类型
- 为什么我不能在类中使用参数化构造函数?
- 为什么我不能使用 std::unique_ptr 作为"模板<class>类"参数?
- C++ _beginthread不能将字符串作为参数传递
- 不能使用嵌套结构中的联合元素作为 scanf() 的参数来存储所需的值
- 为什么模板引用类型不能用作模板类型别名参数?
- 不能将指针用作默认模板参数
- 混合 c++ 和汇编不能将多个参数从C++函数传递到程序集
- 为什么编译器不能从返回类型中推断出模板参数?
- 为什么此参数包不能接受函数指针?
- 为什么不能将此参数包直接解压缩到向量初始值设定项列表中?
- 为什么不能订购函数参数评估
- 使用 std::vector<Particle> 粒子;函数 .at() 不能与迭代器一起使用,它作为 for 循环中的参数