2015-04-16 2 views
8

Я пытаюсь передать итератор в качестве параметра шаблона к методу шаблона, но компилятор жалуется:Не удается вывести тип шаблона

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

возможно дубликат [Обход для не выводил контекста] (http://stackoverflow.com/questions/8308213/workaround-for-non-deduced-context) – vsoftco

ответ

13

Причина заключается в том, что форма у вас есть 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); 

Там нет понятия «контейнер» здесь вообще - это просто тип итератора, который должен быть выведен. Это часть красоты библиотеки алгоритмов.

Так что, если то, что вы хотите сделать, это просто выводит содержимое итератора, правильная функция будет просто:

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

Когда вы звоните Assert(myVec.cbegin()), Iterator получите выводится как std::vector<double>::const_iterator, что именно то, что вы хотите.

+0

Понравилось, как вы это объяснили – Ajay

+0

Отлично! Спасибо. –

1

Стандартные алгоритмы выглядеть следующим образом:

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

Если им нужен тип итератора, они могут использовать typename std::iterator_traits<Iterator>::value_type.

То, что они не делают, является ссылкой на контейнер, такой как vector. Не все итераторы исходят из контейнеров.

+0

было бы неплохо показать, что это будет выглядеть в этом примере. – Alex

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

Вот и все: стандартная библиотека просто параметризует весь тип итератора. Фактически, все, что ведет себя как итератор, может быть использовано (это основная причина, почему итераторы ведут себя как указатели). Это называется «утиная печать».

То, что вы пытаетесь сделать (ограничение функции только теми типами, которые являются явными итераторами), - это то, о чем понятия C++ 17.

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

Попробуйте это один раз.

+0

С некоторыми значениями не с пустым вектором – Launa

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