Newsgroup: it.comp.lang.c++
Titolo: could not deduce template argument

salve a tutti,
ho il seguente problema:
ho una funzione "Fun" che prevede un parametro di tipo "Base" (una
struttura costituita da due iteratori) e vorrei poter chiamare Fun con
un parametro di tipo stringa (in tal deve usare gli iteratori begin ()
ed end ())
potrei aggiungere un overload alla funzione Fun in modo da gestire
anche il caso di argomento di tipo string ma ...
il fatto è che ci sono molte altre funzioni con signature simile e non
vorrei dover prevedere l'overload per ognuna
ho pensato quindi di prevedere una "conversione" tra string e Base e a
tal fine ho definito una struct "Derived" derivata da "Base" che ha un
costruttore con parametro string
risultato: non funziona :-(
sembra che il compilatore non consideri il costruttore di Derived come
modo per costruire un Base: ...in effetti, forse, gli stò chiedendo un
doppio salto mortale...
gradito qualunque idea/commento
il sorgente è riportato sotto
saluti,
Marco
template<class Iter>
struct Base
{
	Base (Iter b, Iter e) :	begin (b), end (e) { }
	Iter	begin;
	Iter	end;
};
template<class Iter>
void Fun (const Base<Iter>& reader)
 { }
struct Derived : public Base<string::const_iterator>
{
	Derived (const string& str) : Base (str.begin (), str.end ()) { }
};
int main ()
{
	string arg;
	Fun (Base<string::const_iterator> (arg.begin (), arg.end ())); // OK
	Fun (Derived (arg)); // OK
	Fun (arg); // error C2784: could not deduce template argument
	return 0;
}

 anche il caso di argomento di tipo string ma ...
rettifico: ovviamente non è possibile perché equivarrebbe a
specializzare parzialmente una funzione template
(... mi ero confuso con uno stato precedente in cui avevo definito la
funzione Fun con due argomenti)

 doppio salto mortale...
Il problema che presenti ha due aspetti: il primo e' come scrivere il
codice corrispondente nel modo piu' generico possibile, in modo da
evitare ripetizioni inutili. Il secondo e' riuscire a chiamare Fun
senza specificare i parametri del template esplicitamente, sfruttando
la deduzione degli argomenti.
Il primo ha molte soluzioni diverse; rispetto alla tua io preferisco
usare una specializzazione di Base come la seguente:
template <>
struct Base<std::string::const_iterator> {
    Base(std::string const & s) : begin(s.begin()), end(s.end()) {}
    std::string::const_iterator begin;
    std::string::const_iterator end;
};
O ancora piu' efficace e' la tecnica usata nella libreria standard,
che consiste per utilizzare una funzione template helper, magari
specializzata, che ha proprio lo scopo di sfruttare la deduzione degli
argomenti.
Il secondo a mio avviso non e' risolvibile senza scrivere
esplicitamente il meccanismo di supporto, si tratti della tua classe
Derived o di un altro meccanismo.  Una chiamata come:
    std::string arg;
    Fun (arg);
ha due problemi: il primo e' che la deduzione degli argomenti dei
template esclude qualsiasi conversione sull'argomento, il secondo e'
che il passaggio da std::string a Base<std::string::const_iterator>
richiede due conversioni definite dall'utente e neanche questo e'
ammesso dal linguaggio.
Ciao,
Nicola

 Nicola
grazie Nicola
ciao,
Marco

questa è la versione più compatta che credo di aver trovato:
#include <string>
using std::string;
using std::pair;
using std::make_pair;
pair<string::const_iterator, string::const_iterator> make_pair (string
const& str)
	{ return pair<string::const_iterator, string::const_iterator>
(str.begin (), str.end ()); }
template<class Iter>
void Fun (const pair<Iter, Iter>& reader)
{
	// do something ...
}
class MyIter
{
};
int main ()
{
	pair<MyIter, MyIter> myPair;
	Fun (myPair); // caso di argomento pair
	string arg;
	Fun (make_pair (arg)); // caso di argomento string, DEVO chiamare
make_pair
	return 0;
}

rettifico (sorry ;-)):
#include <string>
using std::string;
using std::pair;
pair<string::const_iterator, string::const_iterator> string_pair
(string const& str)
	{ return pair<string::const_iterator, string::const_iterator>
(str.begin (), str.end ()); }
template<class Iter>
void Fun (const pair<Iter, Iter>& reader)
{
	// do something ...
}
class MyIter
{
};
int main ()
{
	pair<MyIter, MyIter> myPair;
	Fun (myPair); // caso di argomento pair
	string arg;
	Fun (string_pair (arg)); // caso di argomento string, DEVO chiamare
string_pair
	return 0;
}

 nella realtà vorrei usare boost::tuple
Se gia' usi Boost prova a vedere se Boost.Range non ha gia' tutto
quello che ti serve.
Ciao,
Nicola

 quello che ti serve.
sembra interessante
Boost.Range rientra tra i pezzi di Boost che mi ripromettevo di vedere
ciao,
Marco