Can't deduce template type

2019-02-16 23:10发布

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.

5条回答
Summer. ? 凉城
2楼-- · 2019-02-16 23:15

The following code is compiled ok using 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
查看更多
叼着烟拽天下
3楼-- · 2019-02-16 23:20

The reason is that the form you have T in is a non-deduced context:

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? It's impossible to determine. You'd have to explicitly provide the type... as something like Assert<A>(5).

See also What is a nondeduced context?

since most of the std algorithms can deduce type from iterator.

That's because the standard algorithms just deduce the iterator type, not the container type. For instance std::find is just:

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.

查看更多
迷人小祖宗
4楼-- · 2019-02-16 23:27
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.

查看更多
家丑人穷心不美
5楼-- · 2019-02-16 23:28

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.

What they don't do is reference a container such as vector in any way. Not all iterators come from containers.

查看更多
Emotional °昔
6楼-- · 2019-02-16 23:37
#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.

查看更多
登录 后发表回答