2015-04-16 4 views
8

Ich versuche, einen Iterator als Template-Parameter in einer Vorlage Methode zu übergeben, aber der Compiler beschwert sich, dass ableiten:Kann nicht Vorlagentyp

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

Der Code, der den Fehler erzeugt ist:

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

Ich denke, es gibt eine einfache Möglichkeit, dies zu tun, da die meisten der Std-Algorithmen Typ aus Iterator abzuleiten.

+0

möglich Duplikat [Behelfslösung für nicht-abgeleitete Kontext] (http://stackoverflow.com/questions/8308213/workaround-for-non-deduced-context) – vsoftco

Antwort

13

Der Grund dafür ist, dass das Formular Sie T in haben eine ist nicht abgeleitet Kontext:

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

einen einfacheren Fall betrachtet, zu verstehen, warum:

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

Was soll T ableiten als ? Es ist unmöglich zu bestimmen. Sie müssten den Typ explizit angeben ... wie etwa Assert<A>(5).

Siehe What is a nondeduced context?

auch die meisten der std Algorithmen seit Typ von Iterator ableiten kann.

Das ist, weil die Standard-Algorithmen nur den Typen Iterator ableiten, nicht den Containertyp. Zum Beispiel std::find ist nur:

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

Es gibt kein Konzept von „Container“ hier überhaupt - es ist nur die Iteratortyp, die abgeleitet werden muss. Das ist Teil der Schönheit der Algorithmenbibliothek.

Also, wenn, was Sie tun wollen, nur Ausgabe der Inhalt des Iterator ist, wäre die korrekte Funktion nur sein:

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

Wenn Sie anrufen Assert(myVec.cbegin()) wird Iterator als std::vector<double>::const_iterator ableiten lassen, was genau das ist, was Sie wollen.

+0

Gefällt mir, wie du es erklärt hast – Ajay

+0

Perfekt! Vielen Dank. –

1

Die Standard-Algorithmen wie folgt aussehen:

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

Wenn sie den Typ des Iterators benötigen, sie typename std::iterator_traits<Iterator>::value_type verwenden können.

Was sie nicht tun, ist einen Container wie vector in irgendeiner Weise zu verweisen. Nicht alle Iteratoren stammen aus Containern.

+0

es wäre schön, es tatsächlich zu zeigen, würde in diesem Beispiel aussehen. – Alex

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

Das ist es - die Standardbibliothek parametrisiert nur den ganzen Typ des Iterators. Tatsächlich kann alles, was sich wie ein Iterator verhält, verwendet werden (das ist der Hauptgrund, warum Iteratoren sich wie Zeiger verhalten). Dies wird "Ente tippen" genannt.

Was Sie versuchen zu tun (die Funktion auf nur diejenigen Typen einzuschränken, die explizite Iteratoren sind), das ist es, worum es bei C++ 17-Konzepten geht.

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

Probieren Sie es einmal aus.

+0

Mit einigen Werten nicht mit leerem Vektor – Launa

0

Der folgende Code ist ok mit Clang kompiliert.

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

Die Ausgänge:

$ ./a.out 
2 

Die Version des Compilers:

$ 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