2015-04-16 14 views
8

Sto cercando di passare un iteratore come parametro modello a un metodo di modello, ma il compilatore si lamenta che:Non può dedurre tipo di modello

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

Il codice che genera l'errore è:

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

Sto indovinando c'è un modo semplice per farlo funzionare, dal momento che la maggior parte degli algoritmi std può dedurre il tipo da iteratore.

+0

possibile duplicato di [Soluzione per non dedotta contesto] (http://stackoverflow.com/questions/8308213/workaround-for-non-deduced-context) – vsoftco

risposta

13

La ragione è che la forma si dispone T in è un contesto non dedotta:

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

considerare un caso più semplice per capire perché:

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

Quale dovrebbe T dedurre come ? È impossibile da determinare. Dovresti fornire esplicitamente il tipo ... come qualcosa come Assert<A>(5).

Vedi anche What is a nondeduced context?

poiché la maggior parte degli algoritmi STD può dedurre tipo dall'iteratore.

Questo perché gli algoritmi standard solo dedurre l'iteratore tipo , non il tipo contenitore. Per esempio std::find è solo:

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

non esiste il concetto di "contenitore" qui a tutti - è solo il tipo di iteratore che deve essere dedotto. Questo fa parte della bellezza della libreria degli algoritmi.

Quindi, se ciò che si vuole fare è solo in uscita il contenuto del iteratore, la funzione corretta sarebbe solo:

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

Quando si chiama Assert(myVec.cbegin()), Iterator otterrà dedurre come std::vector<double>::const_iterator, che è esattamente ciò tu vuoi.

+0

Mi è piaciuto il modo in cui lo hai spiegato – Ajay

+0

Perfetto! Grazie. –

1

Gli algoritmi standard simile a questa:

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

Se hanno bisogno il tipo di iteratore, possono utilizzare typename std::iterator_traits<Iterator>::value_type.

Quello che non fanno è riferimento a un contenitore come vector in alcun modo. Non tutti gli iteratori provengono da contenitori.

+0

sarebbe bello effettivamente mostrare che sarebbe guardare in questo esempio. – Alex

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

Ecco fatto: la libreria standard si limita a parametrizzare sull'intero tipo di iteratore. In effetti, qualsiasi cosa che si comporta come un iteratore può essere usata (questa è la ragione principale per cui gli iteratori si comportano come puntatori). Questo è chiamato "duck typing".

Quello che si sta tentando di fare (limitando la funzione solo a quei tipi che sono iteratori espliciti) è il significato dei concetti di 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; 
} 

Provatelo una volta.

+0

Con alcuni valori non con il vettore vuoto – Launa

0

Il seguente codice è compilato ok usando 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; 
} 

Le uscite:

$ ./a.out 
2 

versione del compilatore:

$ 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 
Problemi correlati