简体   繁体   English

无法推断出模板类型

[英]Can't deduce template type

I'm trying to pass an iterator as a template parameter to a template method, but the compiler complains that: 我正在尝试将迭代器作为模板参数传递给模板方法,但编译器抱怨:

error C2783: 'void Test::Assert(std::vector<T>::const_iterator)':
could not deduce template argument for 'T'

The code that produces the error is: 产生错误的代码是:

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

I'm guessing there is a simple way to make this work, since most of the std algorithms can deduce type from iterator. 我猜有一种简单的方法可以使这项工作,因为大多数std算法可以从迭代器中推断出类型。

The reason is that the form you have T in is a non-deduced context : 原因是你有T in的形式是一个非推断的上下文

template <typename T>
void Assert(typename std::vector<T>::const_iterator it)

Consider a simpler case to understand why: 考虑一个更简单的案例来理解为什么:

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

What should T deduce as? T应该推断出什么? It's impossible to determine. 这是不可能确定的。 You'd have to explicitly provide the type... as something like Assert<A>(5) . 你必须明确地提供类型...像Assert<A>(5)

See also What is a nondeduced context? 另请参见什么是非弱化上下文?

since most of the std algorithms can deduce type from iterator. 因为大多数std算法都可以从迭代器推导出类型。

That's because the standard algorithms just deduce the iterator type, not the container type . 那是因为标准算法只推导出迭代器类型,而不是容器类型 For instance std::find is just: 例如std::find就是:

template <class InputIt, class T>
InputIt find( InputIt first, InputIt last, const T& value );

There is no concept of "container" here at all - it's just the iterator type that needs to be deduced. 这里根本没有“容器”的概念 - 它只是需要推导出的迭代器类型。 That's part of the beauty of the algorithms library. 这是算法库之美的一部分。

So if what you want to do is just output the contents of the iterator, the correct function would just be: 因此,如果你想要做的只是输出迭代器的内容,那么正确的函数就是:

template <typename Iterator>
void Assert(Iterator it)
{
    std::cout << *it << std::endl;
}

When you call Assert(myVec.cbegin()) , Iterator will get deduced as std::vector<double>::const_iterator , which is exactly what you want. 当你调用Assert(myVec.cbegin())Iterator将被推导为std::vector<double>::const_iterator ,这正是你想要的。

The standard algorithms look like this: 标准算法如下所示:

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

If they need the type of the iterator, they can use typename std::iterator_traits<Iterator>::value_type . 如果它们需要迭代器的类型,则可以使用typename std::iterator_traits<Iterator>::value_type

What they don't do is reference a container such as vector in any way. 他们不做的是以任何方式引用诸如vector的容器。 Not all iterators come from containers. 并非所有迭代器都来自容器。

template <typename Ite>
void Assert(Ite &&it)
{
    std::cout << *std::forward<It>(it) << std::endl;
}

That's it - the standard library just parameterizes on the whole type of the iterator. 就是这样 - 标准库只是对整个迭代器类型进行参数化。 In fact, anything that behaves like an iterator can be used (that's the main reason why iterators behave like pointers). 实际上,可以使用任何行为类似于迭代器的东西(这是迭代器表现得像指针的主要原因)。 This is called "duck typing". 这被称为“鸭子打字”。

What you are trying to do (restricting the function to only those types which are explicit iterators) is what C++17 concepts are about. 你要做的是什么(将函数限制为只有那些显式迭代器的类型)才是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;
}

Try out this once. 尝试一次。

The following code is compiled ok using clang. 使用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;
}

The outputs: 产出:

$ ./a.out
2

The compiler's version: 编译器的版本:

$ 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM