PDA

View Full Version : [C++] funzione che ritorna vector<?>


trallallero
03-01-2008, 15:45
Sto cominciando ad usare STL solo adesso e mi servirebbe (se possibile) creare una
funzione che ritorna un vector<tipo> dove tipo può essere
(per adesso) un int o double

si può e, se si, come si fa ?

grazie

cionci
03-01-2008, 16:29
Fai una funzione template ;)

template <class T>
vector<T> funzione();

trallallero
03-01-2008, 16:33
Fai una funzione template ;)

template <class T>
vector<T> funzione();

così semplice ? :eek:

EDIT:
ho googlato questo:
vector "unknown type" return function c++
ed è uscito l'impossibile :D

grazie

cionci
03-01-2008, 16:35
Certo ;)

Dopo per richiamarla:

vector<int> v = funzione<int>();
vector<double> v = funzione<double>();

trallallero
03-01-2008, 16:38
Certo ;)

Dopo per richiamarla:

vector<int> v = funzione<int>();
vector<double> v = funzione<double>();

infatti, già prevedevo una richiesta di aiuto per la chiamata alla funzione
vabbè grazie di nuovo.

Certo che è potente 'sto STL ... anche se in certe occasioni preferisco ancora usare funzioni C tipo strstr, strchr etc

cionci
03-01-2008, 16:41
anche se in certe occasioni preferisco ancora usare funzioni C tipo strstr, strchr etc
Male...le string funzionano alla grande per fare quelle cose ;)

trallallero
04-01-2008, 08:28
Male...le string funzionano alla grande per fare quelle cose ;)

'nsomma ... o forse sono io che non avendo molta dimestichezza con l'STL (e poca paziena :D) preferisco usare le low-level ones

quello che non mi piace è che le varie find tornano sempre un indice e mai un char pointer quindi, trovato per esempio il valore, devi fare una substr illeggibile,
A sto punto meglio un return strstr(...)

è anche vero che certe volte ti semplificano la vita come per esempio in quest trim che ho fatto
string Util::trimString( const string& s )
{
unsigned int begin = s.find_first_not_of(' ');
unsigned int end = s.find_last_not_of (' ');

return s.substr( begin, end-begin+1);
}


senza STL sarebbe sicuramente più illeggibile

cionci
04-01-2008, 08:40
Appunto...basta lavorare esclusivamente con le string e sei a posto...poi se devi usare qualche libreria che ha come parametri char * basta convertire con c_str().

trallallero
04-01-2008, 09:04
Appunto...basta lavorare esclusivamente con le string e sei a posto...poi se devi usare qualche libreria che ha come parametri char * basta convertire con c_str().

scusa se insisto ma a questo punto vorrei sapere come faresti questa funzione senza l'uso di un rapido strchr.
È una funzione che cerca una stringa delimitata da certi caratteri in una stringa sorgente. Ho usato sia string che funzioni C

All'inizio pSrc era di tipo string& poi ho sbroccato (non ricordo perchè ma per colpa di 'ste string) ed ho messo char*

string LLUtils::GetDelimitedString( const char* pSrc, int LeftDelimiter, int RightDelimiter )
{
LogL.Write( LogLib::LOGLIB_DEBUG_FLOW_MSG, LOGLIB_FIX_ARGS, 0, "" );

if (pSrc) // so the caller can avoid checking
{
char* start = strchr( pSrc, LeftDelimiter );
if (start) // left delimiter was found
{
while(*(++start) == ' ')
; // skip left spaces

char* end = strchr( start, RightDelimiter );
if (end) // right delimiter was found
{
while(*(--end) == ' ')
; // skip right spaces

string s(pSrc); // create the string to be returned
s.substr( (start - pSrc) );
return s.substr( (start - pSrc), (end - start + 1) );
}
}
}
return "";
}
////////////////////////////////////////////////////////////////////

variabilepippo
04-01-2008, 09:14
scusa se insisto ma a questo punto vorrei sapere come faresti questa funzione senza l'uso di un rapido strchr.


Potresti determinare gli indici da passare a tuastringa.substr con i metodi find e rfind della classe string. :)

cionci
04-01-2008, 09:22
Vediamo:

string LLUtils::GetDelimitedString( const string &src, int LeftDelimiter, int RightDelimiter )
{
LogL.Write( LogLib::LOGLIB_DEBUG_FLOW_MSG, LOGLIB_FIX_ARGS, 0, "" );

string result = "";
size_t left = src.find_first_of(LeftDelimiter);
size_t right = src.find_last_of(RightDelimiter);

if(left != str::npos && right != str::npos)
{
result = Util::trimString(src.substr(left, right));
}
return result;
}

Se ho capito bene ;)

trallallero
04-01-2008, 09:40
Potresti determinare gli indici da passare a tuastringa.substr con i metodi find e rfind della classe string. :)

...
Se ho capito bene ;)

ecco, come volevasi dimostrare ... Cionci hai capito bene anzi, benissimo :D

Praticamente ci ho litigato per un pò, poi ho optato per ciò che conosco benissimo per non perdere tempo prezioso e invece era fattibilissimo.

vabbè, grazie ancora :)

trallallero
04-01-2008, 09:57
beh, visto che orami è una disputa (amichevole e costruttiva - per me almeno) tra STL e C functions, vorrei proporvi un'altra ... gara :D
(ed è quì che mi serviva una funzione che torna vector<type>)

ho una stringa di questo formato "x < y" dove x è un valore minimo e y quello massimo.
La funzione torna un vector di interi dal minimo al massimo.
Quindi se il minimo è 1 e il massimo 5, torna
1 2 3 4 5

Calcolando che il tutto deve essere il più veloce possibile (sto lavorando ad un progetto per la comunicazione tra un carro armato e vari operatori) l'ho fatta così
(io avrei fatto a meno anche del lento vector e fatto tutto con un array di int :stordita: )

vector<int> LLUtils::GetMinToMaxValues( string& s, int Separator )
{
vector<int> v;

int Min = atoi( s.c_str() ); // 1st value, atoi stops at first non digit char
int Max = atoi( strchr(s.c_str(), Separator) + 1 ); // 2nd value, atoi from char after Separator

for ( int i = Min; i <= Max; ++i )
v.push_back(i); // creates the list
return v;
}

cionci
04-01-2008, 10:17
Certo che anche la tua non va male...ma quando posso tento di non mischiare C e C++.
Il codice sotto in teoria non necessita del parametro separator...sempre che il separatore fra i numeri non sia composto da diversi caratteri con spazi nel mezzo...
Quindi a seconda delle specifiche del problema la tua potrebbe andare meglio di quella che ho scritto sotto. Se il formato è sempre quello che mi hai scritto "3 > 10" però va sempre bene.

vector<int> LLUtils::GetMinToMaxValues(const string& s)
{
int min, max;
string separator;
istringstream iss(s);
iss >> min >> separator >> min;

for ( int i = Min; i <= Max; ++i )
v.push_back(i); // creates the list
return v;
}

trallallero
04-01-2008, 10:30
Certo che anche la tua non va male...ma quando posso tento di non mischiare C e C++.
Il codice sotto in teoria non necessita del parametro separator...sempre che il separatore fra i numeri non sia composto da diversi caratteri con spazi nel mezzo...
Quindi a seconda delle specifiche del problema la tua potrebbe andare meglio di quella che ho scritto sotto. Se il formato è sempre quello che mi hai scritto "3 > 10" però va sempre bene.

vector<int> LLUtils::GetMinToMaxValues(const string& s)
{
int min, max;
string separator;
istringstream iss(s);
iss >> min >> separator >> min;

for ( int i = Min; i <= Max; ++i )
v.push_back(i); // creates the list
return v;
}

uhm ... figata come tecnica ma non andrebbe bene nei valori multipli.

Ho Min to Max, Min & Max, e valori multipli separati da |
Però grazie, interessante ;)

cionci
04-01-2008, 10:34
Fammi un esempio di valori multipli...

trallallero
04-01-2008, 10:41
Fammi un esempio di valori multipli...

non ne abbiamo ancora ma la settimana prossima arriveranno i dati di configurazione di un dispositivo radio che dovrà far parte della comunicazione.
Ma da quello che ho capito sono solo interi quindi la stringa potrebbe essere qualcosa come:
"1 | 3 | 12 | 45"

ovviamente possono essere 1 così come 10.000 ...


Pensavo di aver già fatto la funzione invece non la trovo ... mi sa che devo dormire un pò di più e lavorare un pò di meno ... :D

EDIT: ah ecco, avevo fatto qualcosa trovando degli esempi STL in internet:

bool LLElementHandler::GetFields( string & text, string & separators, list<string> &words )
{
LogL.Write( LogLib::LOGLIB_DEBUG_FLOW_MSG, LOGLIB_FIX_ARGS, 0, "" );

int n = text.length();
int start, stop;

start = text.find_first_not_of(separators);

while ((start >= 0) && (start < n))
{
stop = text.find_first_of(separators, start);
if ((stop < 0) || (stop > n))
stop = n;

words.push_back( text.substr(start, stop - start) );
start = text.find_first_not_of(separators, stop + 1);
}
return true;
}

però mi sa di lento ... :rolleyes:

cionci
04-01-2008, 11:13
Se sono separati da spazio e da un altro carattere:

#include <sstream>
#include <iostream>
#include <vector>

using namespace std;


vector<int> parse(const string &s)
{
istringstream iss(s);
vector<int> v;
string separator;

while (!iss.fail())
{
int tmp;
iss >> tmp;
if (!iss.fail()) v.push_back(tmp);
iss >> separator;
}
return v;
}


int main()
{
vector<int> v = parse("1 | 3 | 5 | 5");
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
cout << *it << " ";
cout << endl;

v = parse("1 < 5");
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
cout << *it << " ";
cout << endl;

return 0;
}

trallallero
04-01-2008, 11:23
in pratica se non da errore è un intero e lo copi in list, l'ultimo errore fa uscire.
Interessante ...

in C è più corto ed elegante :O

v.push_back(atoi(c));
while( c = strchr(c, Separator) )
v.push_back(atoi(++c));

scherzo ovviamente.
Insomma con 'sto STL se pò fà tutto ... mi devo solo abituare ad usarlo ... addio C :cry:

trallallero
04-01-2008, 12:34
ultimissima, lo giuro :stordita:

sto applicando ciò che m'hai scritto (template)
ma adesso che non so che tipo è, come faccio a estrapolare i dati ?
Ovviamente non posso più fare atoi, quindi ?

template <class T> vector<T> LLUtils::GetMinToMaxValues( string& s, int Separator )
{
vector<T> v;

int Min = atoi( s.c_str() );
int Max = atoi( strchr(s.c_str(), Separator) + 1 );

for ( int i = Min; i <= Max; ++i )
v.push_back(i);
return v;
}

trallallero
04-01-2008, 12:42
forse così ?

template <class T> vector<T> LLUtils::GetMinToMaxValues( string& s, int Separator )
{
vector<T> v;

T Min = s.find_first_not_of(Separator);
T Max = s.find_last_not_of (Separator);

for ( T i = Min; i <= Max; ++i )
v.push_back(i);
return v;
}


EDIT: 'zzo ho scritto ? :eek:

cionci
04-01-2008, 13:42
Questo è tutto un altro discorso :)
Allora devi sapere prima il tipo di dato...che tipi di dati puoi avere ?

trallallero
04-01-2008, 14:16
Questo è tutto un altro discorso :)
Allora devi sapere prima il tipo di dato...che tipi di dati puoi avere ?

ho lasciato perdere anche perchè mi dava un errore terribile il linker ...
il problema comunque è che non posso fare una lista da min a max proprio perchè non conosco il tipo di dato.
E comunque ho visto che il tipo dovrebbe essere solo int quindi uso solo int e taglio la testa al toro

Ma magari nelle altre funzioni dove estrapola solo i valori presenti nella lista si può fare

Se poi hai qualche mandrakata in mente sono quì :D