Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 823
Q-bertsuit Avatar asked Apr 16 '15 14:04

Q-bertsuit


2 Answers

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.

like image 100
Barry Avatar answered Nov 09 '22 12:11

Barry


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.

like image 28
Sebastian Redl Avatar answered Nov 09 '22 13:11

Sebastian Redl