我正在 C++ 中使用模板和类型推导,并在使用 std::span 但不使用原始指针时遇到类型推导失败。下面是我的代码的简化版本:
#include <span>
#include <vector>
template <typename T>
void f1(std::span<const T> param)
{}
template <typename T>
void f2(const T* param)
{}
int main()
{
std::vector<int> v{1,2,3};
std::span<int> s{v};
// f1(s); // Uncommenting this line causes a compilation error: cannot deduce a type for 'T' that would make 'const T' equal 'int'
int x = 10;
int* px = &x;
const int* z = px;
f2(px); // Works fine
f2(z); // Works fine
}
当我取消注释 f1(s) 调用时,我收到一条编译错误,指出编译器无法推导出“T”的类型,从而使“const T”等于“int”。然而,类似的指针模板函数(如 f2)在传递 int* 和 const int* 时编译不会出现任何问题。
为什么 std::span 会出现此错误,而指针则不会?
std::span<T>
可以隐式转换为 std::span<const T>
。因此,如果函数中的 T
是 int
,则您的 std::span<int>
参数可以转换为函数所需的 std::span<const int>
。然而,这并不意味着编译器能够在其模板参数推导过程中弄清楚这一点。
编译器的模板参数推导过程并不关心什么可以转换成什么。它需要
T
的一些参数,以便 std::span<const T>
与 std::span<int>
相同,正如错误消息中所说,没有参数,因为没有。如果 T
是一个 int
,正如我上面所说,std::span<const T>
将是一个 std::span<const int>
,可以从 std::span<int>
隐式转换。 但它仍然不是编译器想要的完全相同的类型,因此该选项被排除在外。
您可以通过两种方式解决此问题:
f1<int>(s)
而不是f1(s)
。这避免了任何模板参数推导。s
变为 std::span<const int>
,而不是像当前那样成为 std::span<int>
。现在确实存在一个类型 T
,使得 std::span<const T>
是 std::span<const int>
,并且编译器将正确识别并使用它。