无法推断模板类型
Can't deduce template type
本文关键字:类型 更新时间:2023-10-16
我试图将迭代器作为模板参数传递给模板方法,但编译器抱怨:
error C2783: 'void Test::Assert(std::vector<T>::const_iterator)':
could not deduce template argument for 'T'
产生错误的代码是:
#include "stdafx.h"
#include <iostream>
#include <vector>
class Test
{
public:
template <typename T>
void Assert(typename std::vector<T>::const_iterator it)
{
std::cout << *it << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Test test;
std::vector<double> myVec;
test.Assert(myVec.cbegin());
return 0;
}
我猜有一种简单的方法可以实现这一点,因为大多数std算法都可以从迭代器中推导类型。
原因是T
所在的表单是非推导上下文:
template <typename T>
void Assert(typename std::vector<T>::const_iterator it)
考虑一个更简单的案例来理解原因:
struct A { using type = int; };
struct B { using type = int; };
struct C { using type = int; };
template <typename T>
void Assert(typename T::type it) { ... }
Assert(5);
T
应该推导为什么?无法确定。您必须显式地提供类型。。。类似于CCD_ 3。
另请参阅什么是非退化上下文?
因为大多数std算法都可以从迭代器中推导类型。
这是因为标准算法只是推导迭代器类型,而不是容器类型。例如,std::find
只是:
template <class InputIt, class T>
InputIt find( InputIt first, InputIt last, const T& value );
这里根本没有"容器"的概念——它只是需要推导的迭代器类型。这就是算法库之美的一部分。
因此,如果您只想输出迭代器的内容,那么正确的函数应该是:
template <typename Iterator>
void Assert(Iterator it)
{
std::cout << *it << std::endl;
}
当你调用Assert(myVec.cbegin())
时,Iterator
会被推导为std::vector<double>::const_iterator
,这正是你想要的。
标准算法如下所示:
template <typename Iterator>
void some_algorithm(Iterator first, Iterator last) {
// do stuff
}
如果他们需要迭代器的类型,他们可以使用typename std::iterator_traits<Iterator>::value_type
。
他们不会以任何方式引用vector
这样的容器。并非所有迭代器都来自容器。
template <typename Ite>
void Assert(Ite &&it)
{
std::cout << *std::forward<It>(it) << std::endl;
}
就是这样——标准库只是对迭代器的整个类型进行参数化。事实上,任何表现得像迭代器的东西都可以使用(这就是迭代器表现得像指针的主要原因)。这被称为"鸭子打字"。
您所要做的(将函数限制为仅属于显式迭代器的类型)就是C++17概念的意义所在。
#include "stdafx.h"
#include <iostream>
#include <vector>
class Test
{
public:
template <typename T>
void Assert(typename T::const_iterator it)
{
std::cout << *it << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Test test;
std::vector<double> myVec;
test.Assert<std::vector<double> >(myVec.cbegin());
return 0;
}
试试这个。
以下代码是使用clang编译的。
#include <iostream>
#include <vector>
class Test
{
public:
template <typename T>
void Assert(typename std::vector<T>::const_iterator it)
{
std::cout << *it << std::endl;
}
};
int main(int argc, char* argv[])
{
Test test;
std::vector<double> myVec;
myVec.push_back(2.0f);
test.Assert<double>(myVec.cbegin()); // call Assert in this way.
return 0;
}
输出:
$ ./a.out
2
编译器版本:
$ clang++ -v
Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM
3.6.0svn) Target: x86_64-apple-darwin14.1.0 Thread model: posix
相关文章:
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 访问者访问变体并返回不同类型时出错
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 模板元程序查找相似的连续类型名称
- 是否可以从int转换为enum类类型
- 构造函数正在调用一个使用当前类类型的函数
- 我应该使用什么来代替void作为变体中的替代类型之一
- 类中的字符串不命名类型