12

我试图将迭代器作为模板参数传递给模板方法,但编译器抱怨:

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;
}

我猜有一种简单的方法可以完成这项工作,因为大多数标准算法都可以从迭代器中推断出类型。

4

5 回答 5

15

原因是您拥有的形式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).

另请参阅什么是非演绎上下文?

因为大多数标准算法都可以从迭代器中推断出类型。

那是因为标准算法只是推导出迭代器类型,而不是容器类型。例如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,这正是您想要的。

于 2015-04-16T14:30:17.103 回答
2

标准算法如下所示:

template <typename Iterator>
void some_algorithm(Iterator first, Iterator last) {
  // do stuff
}

如果他们需要迭代器的类型,他们可以使用typename std::iterator_traits<Iterator>::value_type.

他们不做的是以vector任何方式引用容器。并非所有迭代器都来自容器。

于 2015-04-16T14:25:58.843 回答
0
template <typename Ite>
void Assert(Ite &&it)
{
    std::cout << *std::forward<It>(it) << std::endl;
}

就是这样——标准库只是对迭代器的整个类型进行参数化。事实上,任何表现得像迭代器的东西都可以使用(这就是迭代器表现得像指针的主要原因)。这被称为“鸭子打字”。

您正在尝试做的事情(将函数限制为仅是显式迭代器的那些类型)是 C++17 概念的含义。

于 2015-04-16T14:27:02.017 回答
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;
}

试试这个。

于 2015-04-16T14:44:11.227 回答
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
于 2015-04-16T14:59:19.040 回答