我试图将迭代器作为模板参数传递给模板方法,但编译器抱怨说:
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算法都可以从迭代器中推断出类型。
答案 0 :(得分:14)
原因是您拥有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
应该推断出什么?这是不可能确定的。您必须明确提供类型...类似于Assert<A>(5)
。
另见What is a nondeduced context?
因为大多数std算法都可以从迭代器推导出类型。
这是因为标准算法只推断出迭代器类型,而不是容器类型。例如std::find
只是:
template <class InputIt, class T>
InputIt find( InputIt first, InputIt last, const T& value );
没有&#34;容器&#34;的概念。在这里 - 它只是需要推导出的迭代器类型。这是算法库之美的一部分。
因此,如果您想要做的只是输出迭代器的内容,那么正确的函数就是:
template <typename Iterator>
void Assert(Iterator it)
{
std::cout << *it << std::endl;
}
当您致电Assert(myVec.cbegin())
时,Iterator
将被推断为std::vector<double>::const_iterator
,这正是您想要的。
答案 1 :(得分:2)
标准算法如下所示:
template <typename Iterator>
void some_algorithm(Iterator first, Iterator last) {
// do stuff
}
如果他们需要迭代器的类型,他们可以使用typename std::iterator_traits<Iterator>::value_type
。
他们不做的是以任何方式引用vector
之类的容器。并非所有迭代器都来自容器。
答案 2 :(得分:0)
template <typename Ite>
void Assert(Ite &&it)
{
std::cout << *std::forward<It>(it) << std::endl;
}
就是这样 - 标准库只是对整个迭代器类型进行参数化。实际上,可以使用任何行为类似于迭代器的东西(这是迭代器表现得像指针的主要原因)。这被称为“鸭子打字”。
您正在尝试做的事情(将函数仅限于那些显式迭代器的类型)是C ++ 17概念的内容。
答案 3 :(得分:0)
#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;
}
尝试一次。
答案 4 :(得分: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