read_data code

G

Gary Wessle

Hi

I wrote this routine below but getting the error below it which I
don't know how to fix.

thanks


//useful.h
/**
Reads data from file into a given type vector.
@param string full path to file containing the data
@param short int column number to return in a vector
@param char type of data s-string, d-double, i-int
...
@return vector<type_selected_as_above>
*/
template<class T>
vector<T> get_data(string, short, char);

****************************************************************
//useful.cpp

template<class T> vector<T> get_data(string s,
short sh,
char ch){
sh--;
ifstream in(s.c_str());
string line;
vector<string> vs;
vector<double> vd;
vector<int> vi;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vs.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vd.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vi.push_back(it);
default:
cout << "type not known" << endl;
}
}
switch(ch){
case 's':return vs;
case 'd':return vd;
case 'i':return vi;
}
}
****************************************************************
int main(){
string f = "/data/home/activity.dat";
vector<string> vss = get_data(f, 1, 's'); //line 40 error


typedef vector<string>::iterator ITER;
ITER iterEnd = vss.end();
for (ITER iter = vss.begin(); iter != iterEnd; ++iter)
copy(iter->begin(), iter->end(), ostream_iterator<string>(cout, endl));


****************************************************************
main.cpp:40: error: no matching function for call to
'get_data(std::string&, int, char)'

main.cpp:46: error: no matching function for call to
'std::eek:stream_iterator<std::basic_string<char, std::char_traits<char>,
 
K

Kai-Uwe Bux

Gary said:
Hi

I wrote this routine below but getting the error below it which I
don't know how to fix.

thanks


//useful.h
/**
Reads data from file into a given type vector.
@param string full path to file containing the data
@param short int column number to return in a vector
@param char type of data s-string, d-double, i-int
...
@return vector<type_selected_as_above>
*/
template<class T>
vector<T> get_data(string, short, char);

****************************************************************
//useful.cpp

template<class T> vector<T> get_data(string s,
short sh,
char ch){
sh--;

Strange: sh is only used in this statement, which in turn has no further
consequences.
ifstream in(s.c_str());
string line;
vector<string> vs;
vector<double> vd;
vector<int> vi;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vs.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vd.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vi.push_back(it);
default:
cout << "type not known" << endl;
}
}
switch(ch){
case 's':return vs;
case 'd':return vd;
case 'i':return vi;

You can't do that: a function can only return a value of the type specified
in its signature. You did not (and cannot) define a function that returns a
template. You defined a template function, i.e., a family of functions
parameterized by the template parameters.
}
}
****************************************************************
int main(){
string f = "/data/home/activity.dat";
vector<string> vss = get_data(f, 1, 's'); //line 40 error


typedef vector<string>::iterator ITER;
ITER iterEnd = vss.end();
for (ITER iter = vss.begin(); iter != iterEnd; ++iter)
copy(iter->begin(), iter->end(), ostream_iterator<string>(cout,
endl));


****************************************************************
main.cpp:40: error: no matching function for call to
'get_data(std::string&, int, char)'

Overload resolution is not based on return types. Thus, the compiler has no
idea why it should have a look at the templated get_data() function. You
would need to call it like:

vector said:
main.cpp:46: error: no matching function for call to
'std::eek:stream_iterator<std::basic_string<char, std::char_traits<char>,

Probably, you want the endl to be "\n".


Best

Kai-Uwe Bux
 
G

Gary Wessle

Kai-Uwe Bux said:
Strange: sh is only used in this statement, which in turn has no further
consequences.


You can't do that: a function can only return a value of the type specified
in its signature. You did not (and cannot) define a function that returns a
template. You defined a template function, i.e., a family of functions
parameterized by the template parameters.

so what would the return statement look like?

return vector<T> vT;

then I have to modify the code to use vT and not 3 different
vectors based on the type selected. am I in the right track?

template<class T> vector<T> get_data(string s,
short sh,
char ch){
if(sh) sh--; //index is less than number selection
ifstream in(s.c_str());
string line;
vector<T> vT;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vT.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vT.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vT.push_back(it);
default:
cout << "type not known" << endl;
}
}
return vT;
}
}

but this gives me.....
/main.cpp:43: undefined reference
to `std::vector<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > >
get_data<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, short, char)'

the line in question in the main() is this

vector<string> vss = get_data<string>(f, 1, 's');
 
K

Kai-Uwe Bux

Gary said:
Kai-Uwe Bux said:
Gary Wessle wrote:
[snip]
//useful.h
/**
Reads data from file into a given type vector.
@param string full path to file containing the data
@param short int column number to return in a vector
@param char type of data s-string, d-double, i-int
...
@return vector<type_selected_as_above>
*/
template<class T>
vector<T> get_data(string, short, char);

****************************************************************
//useful.cpp

template<class T> vector<T> get_data(string s,
short sh,
char ch){
sh--;

Strange: sh is only used in this statement, which in turn has no further
consequences.
ifstream in(s.c_str());
string line;
vector<string> vs;
vector<double> vd;
vector<int> vi;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vs.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vd.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vi.push_back(it);
default:
cout << "type not known" << endl;
}
}
switch(ch){
case 's':return vs;
case 'd':return vd;
case 'i':return vi;

You can't do that: a function can only return a value of the type
specified in its signature. You did not (and cannot) define a function
that returns a template. You defined a template function, i.e., a family
of functions parameterized by the template parameters.

so what would the return statement look like?

return vector<T> vT;
Yes.

then I have to modify the code to use vT and not 3 different
vectors based on the type selected.
Yes.


am I in the right track?

Well, ...
template<class T> vector<T> get_data(string s,
short sh,
char ch){
if(sh) sh--; //index is less than number selection
ifstream in(s.c_str());
string line;
vector<T> vT;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vT.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vT.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vT.push_back(it);
default:
cout << "type not known" << endl;
}
}
return vT;
}
}

That still won't fly: you are invoking vT.push_back() for string, double,
and int arguments. That does not work. You can only use vT.push_back() to
put an element of type T into vT.

[snip]


What is the underlying problem that you are trying to solve. It looks as
though you are making things way more complicated than they should be.


Best

Kai-Uwe Bux
 
G

Gary Wessle

Gary Wessle said:
so what would the return statement look like?

return vector<T> vT;

then I have to modify the code to use vT and not 3 different
vectors based on the type selected. am I in the right track?

template<class T> vector<T> get_data(string s,
short sh,
char ch){
if(sh) sh--; //index is less than number selection
ifstream in(s.c_str());
string line;
vector<T> vT;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vT.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vT.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vT.push_back(it);
default:
cout << "type not known" << endl;
}
}
return vT;
}
}

but this gives me.....
/main.cpp:43: undefined reference
to `std::vector<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > >
get_data<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, short, char)'

the line in question in the main() is this

vector<string> vss = get_data<string>(f, 1, 's');


but even after fixing this problem, it still will not do what I meant
it to do because the
while(input >> st) will put the stream in input into st, but st is of
a predefined type, well, what if the file has the first column a
string but st happen to be double.
 
G

Gary Wessle

Kai-Uwe Bux said:
Gary said:
Kai-Uwe Bux said:
Gary Wessle wrote:
[snip]
//useful.h
/**
Reads data from file into a given type vector.
@param string full path to file containing the data
@param short int column number to return in a vector
@param char type of data s-string, d-double, i-int
...
@return vector<type_selected_as_above>
*/
template<class T>
vector<T> get_data(string, short, char);

****************************************************************
//useful.cpp

template<class T> vector<T> get_data(string s,
short sh,
char ch){
sh--;

Strange: sh is only used in this statement, which in turn has no further
consequences.

ifstream in(s.c_str());
string line;
vector<string> vs;
vector<double> vd;
vector<int> vi;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vs.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vd.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vi.push_back(it);
default:
cout << "type not known" << endl;
}
}
switch(ch){
case 's':return vs;
case 'd':return vd;
case 'i':return vi;

You can't do that: a function can only return a value of the type
specified in its signature. You did not (and cannot) define a function
that returns a template. You defined a template function, i.e., a family
of functions parameterized by the template parameters.

so what would the return statement look like?

return vector<T> vT;
Yes.

then I have to modify the code to use vT and not 3 different
vectors based on the type selected.
Yes.


am I in the right track?

Well, ...
template<class T> vector<T> get_data(string s,
short sh,
char ch){
if(sh) sh--; //index is less than number selection
ifstream in(s.c_str());
string line;
vector<T> vT;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vT.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vT.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vT.push_back(it);
default:
cout << "type not known" << endl;
}
}
return vT;
}
}

That still won't fly: you are invoking vT.push_back() for string, double,
and int arguments. That does not work. You can only use vT.push_back() to
put an element of type T into vT.

[snip]



template<class T> vector<T> get_data(string s,
short sh,
char ch){
if(sh) sh--;
ifstream in(s.c_str());
string line;
vector<T> vT;
T tok;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
while( input >> tok)
if(sh == j++) vT.push_back(tok);
}
return vT;
}

/main.cpp:43: undefined reference
to `std::vector<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > >
get_data<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >(std::basic_string<char,
What is the underlying problem that you are trying to solve. It looks as
though you are making things way more complicated than they should be.

I am trying to return a vector of whatever type the client selects,
i.e
if we have a file with
1/1/1970 Sam 1934.344
....

and the client calls the function like this.
vector<string> ss = get_data<string>(file_path, 1, 's'); then the
function should put all the dates in the first column in a
vector<string> and return that. or a vector of all the numbers in the
third column in case of
vector<double> ii = get_data<double>(file_path, 3, 'i');
 
G

Gary Wessle

Gary Wessle said:
Kai-Uwe Bux said:
Gary said:
Gary Wessle wrote:
[snip]
//useful.h
/**
Reads data from file into a given type vector.
@param string full path to file containing the data
@param short int column number to return in a vector
@param char type of data s-string, d-double, i-int
...
@return vector<type_selected_as_above>
*/
template<class T>
vector<T> get_data(string, short, char);

****************************************************************
//useful.cpp

template<class T> vector<T> get_data(string s,
short sh,
char ch){
sh--;

Strange: sh is only used in this statement, which in turn has no further
consequences.

ifstream in(s.c_str());
string line;
vector<string> vs;
vector<double> vd;
vector<int> vi;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vs.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vd.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vi.push_back(it);
default:
cout << "type not known" << endl;
}
}
switch(ch){
case 's':return vs;
case 'd':return vd;
case 'i':return vi;

You can't do that: a function can only return a value of the type
specified in its signature. You did not (and cannot) define a function
that returns a template. You defined a template function, i.e., a family
of functions parameterized by the template parameters.


so what would the return statement look like?

return vector<T> vT;
Yes.

then I have to modify the code to use vT and not 3 different
vectors based on the type selected.
Yes.


am I in the right track?

Well, ...
template<class T> vector<T> get_data(string s,
short sh,
char ch){
if(sh) sh--; //index is less than number selection
ifstream in(s.c_str());
string line;
vector<T> vT;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vT.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vT.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vT.push_back(it);
default:
cout << "type not known" << endl;
}
}
return vT;
}
}

That still won't fly: you are invoking vT.push_back() for string, double,
and int arguments. That does not work. You can only use vT.push_back() to
put an element of type T into vT.

[snip]



template<class T> vector<T> get_data(string s,
short sh,
char ch){
if(sh) sh--;
ifstream in(s.c_str());
string line;
vector<T> vT;
T tok;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
while( input >> tok)
if(sh == j++) vT.push_back(tok);
}
return vT;
}

/main.cpp:43: undefined reference
to `std::vector<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > >
get_data<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >(std::basic_string<char,
What is the underlying problem that you are trying to solve. It looks as
though you are making things way more complicated than they should be.

I am trying to return a vector of whatever type the client selects,
i.e
if we have a file with
1/1/1970 Sam 1934.344
...

and the client calls the function like this.
vector<string> ss = get_data<string>(file_path, 1, 's'); then the
function should put all the dates in the first column in a
vector<string> and return that. or a vector of all the numbers in the
third column in case of
vector<double> ii = get_data<double>(file_path, 3, 'i');

vector<string> vss = get_data<string>(f, 1, string);

template<class T> vector<T> get_data(string s,
short sh,
T tok){
if(sh) sh--;
ifstream in(s.c_str());
string line;
vector<T> vT;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
while( input >> tok)
if(sh == j++) vT.push_back(tok);
}
return vT;
}


????????
 
G

Gary Wessle

Gary Wessle said:
Gary Wessle said:
Kai-Uwe Bux said:
Gary Wessle wrote:


Gary Wessle wrote:

[snip]
//useful.h
/**
Reads data from file into a given type vector.
@param string full path to file containing the data
@param short int column number to return in a vector
@param char type of data s-string, d-double, i-int
...
@return vector<type_selected_as_above>
*/
template<class T>
vector<T> get_data(string, short, char);

****************************************************************
//useful.cpp

template<class T> vector<T> get_data(string s,
short sh,
char ch){
sh--;

Strange: sh is only used in this statement, which in turn has no further
consequences.

ifstream in(s.c_str());
string line;
vector<string> vs;
vector<double> vd;
vector<int> vi;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vs.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vd.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vi.push_back(it);
default:
cout << "type not known" << endl;
}
}
switch(ch){
case 's':return vs;
case 'd':return vd;
case 'i':return vi;

You can't do that: a function can only return a value of the type
specified in its signature. You did not (and cannot) define a function
that returns a template. You defined a template function, i.e., a family
of functions parameterized by the template parameters.


so what would the return statement look like?

return vector<T> vT;

Yes.

then I have to modify the code to use vT and not 3 different
vectors based on the type selected.

Yes.


am I in the right track?

Well, ...

template<class T> vector<T> get_data(string s,
short sh,
char ch){
if(sh) sh--; //index is less than number selection
ifstream in(s.c_str());
string line;
vector<T> vT;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vT.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vT.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vT.push_back(it);
default:
cout << "type not known" << endl;
}
}
return vT;
}
}

That still won't fly: you are invoking vT.push_back() for string, double,
and int arguments. That does not work. You can only use vT.push_back() to
put an element of type T into vT.

[snip]



template<class T> vector<T> get_data(string s,
short sh,
char ch){
if(sh) sh--;
ifstream in(s.c_str());
string line;
vector<T> vT;
T tok;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
while( input >> tok)
if(sh == j++) vT.push_back(tok);
}
return vT;
}

/main.cpp:43: undefined reference
to `std::vector<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > >
get_data<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >(std::basic_string<char,
What is the underlying problem that you are trying to solve. It looks as
though you are making things way more complicated than they should be.

I am trying to return a vector of whatever type the client selects,
i.e
if we have a file with
1/1/1970 Sam 1934.344
...

and the client calls the function like this.
vector<string> ss = get_data<string>(file_path, 1, 's'); then the
function should put all the dates in the first column in a
vector<string> and return that. or a vector of all the numbers in the
third column in case of
vector<double> ii = get_data<double>(file_path, 3, 'i');

vector<string> vss = get_data<string>(f, 1, string);

template<class T> vector<T> get_data(string s,
short sh,
T tok){
if(sh) sh--;
ifstream in(s.c_str());
string line;
vector<T> vT;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
while( input >> tok)
if(sh == j++) vT.push_back(tok);
}
return vT;
}


????????
vector<string> vss = get_data<string>(f, 1);
template<class T> vector<T>
get_data(string s, short sh){
if(sh) sh--;
ifstream in(s.c_str());
string line;
vector<T> vT;
T tok;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
while( input >> tok)
if(sh == j++) vT.push_back(tok);
}
return vT;
}


I give up.
 
K

Kai-Uwe Bux

Gary said:
I am trying to return a vector of whatever type the client selects,
i.e
if we have a file with
1/1/1970 Sam 1934.344
...

and the client calls the function like this.
vector<string> ss = get_data<string>(file_path, 1, 's'); then the
function should put all the dates in the first column in a
vector<string> and return that. or a vector of all the numbers in the
third column in case of
vector<double> ii = get_data<double>(file_path, 3, 'i');

Maybe the following contains some ideas you can use:

#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>


struct line_data {

std::string date;
std::string name;
double d;

}; // line_data

std::eek:stream & operator<< ( std::eek:stream & o_str,
line_data const & l ) {
o_str << l.date
<< " "
<< l.name
<< " "
<< l.d
<< "\n";
return ( o_str );
}

std::istream & operator>> ( std::istream & i_str,
line_data & l ) {
line_data dummy;
i_str >> dummy.date;
i_str >> dummy.name;
i_str >> dummy.d;
if ( i_str ) {
l = dummy;
}
return ( i_str );
}


std::string get_data ( line_data const & l ) {
return ( l.date );
}

std::string get_name ( line_data const & l ) {
return ( l.name );
}

double get_d ( line_data const & l ) {
return ( l.d );
}


int main ( void ) {
std::vector< std::string > name_vector;
std::ifstream file ( "data.txt" );
std::transform( std::istream_iterator< line_data >( file ),
std::istream_iterator< line_data >(),
std::back_inserter( name_vector ),
get_name );

std::copy( name_vector.begin(), name_vector.end(),
std::eek:stream_iterator< std::string >( std::cout, "\n" ) );
}


data.txt:
2006/12/05 Sam 3.4
2007/01/12 Bert 2.718282

output:
Sam
Bert



Best

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Kai-Uwe Bux said:
Gary said:
I am trying to return a vector of whatever type the client selects,
i.e
if we have a file with
1/1/1970 Sam 1934.344
...

and the client calls the function like this.
vector<string> ss = get_data<string>(file_path, 1, 's'); then the
function should put all the dates in the first column in a
vector<string> and return that. or a vector of all the numbers in the
third column in case of
vector<double> ii = get_data<double>(file_path, 3, 'i');

Maybe the following contains some ideas you can use:
[snip]

data.txt:
2006/12/05 Sam 3.4
2007/01/12 Bert 2.718282

output:
Sam
Bert

Here is a variation of the code that actually has a function returning the
vector you want:


#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>


struct line_data {

std::string date;
std::string name;
double d;

}; // line_data

std::eek:stream & operator<< ( std::eek:stream & o_str,
line_data const & l ) {
o_str << l.date
<< " "
<< l.name
<< " "
<< l.d
<< "\n";
return ( o_str );
}

std::istream & operator>> ( std::istream & i_str,
line_data & l ) {
line_data dummy;
i_str >> dummy.date;
i_str >> dummy.name;
i_str >> dummy.d;
if ( i_str ) {
l = dummy;
}
return ( i_str );
}


std::string get_data ( line_data const & l ) {
return ( l.date );
}

std::string get_name ( line_data const & l ) {
return ( l.name );
}

double get_d ( line_data const & l ) {
return ( l.d );
}

template < typename T >
struct getter_traits;

template < typename T >
struct getter_traits< T(*)(line_data const &) > {

typedef T result_type;

};


template < typename T >
std::vector< typename getter_traits<T>::result_type >
get_vector ( std::istream & i_str, T getter ) {
std::vector< typename getter_traits<T>::result_type > result;
std::transform( std::istream_iterator< line_data >( i_str ),
std::istream_iterator< line_data >(),
std::back_inserter( result ),
getter );
return ( result );
}

int main ( void ) {
std::ifstream file ( "data.txt" );
std::vector< std::string > name_vector
= get_vector( file, get_name );

std::copy( name_vector.begin(), name_vector.end(),
std::eek:stream_iterator< std::string >( std::cout, "\n" ) );
}


Best

Kai-Uwe Bux
 
G

Gary Wessle

Kai-Uwe Bux said:
Kai-Uwe Bux said:
Gary said:
What is the underlying problem that you are trying to solve. It looks as
though you are making things way more complicated than they should be.


I am trying to return a vector of whatever type the client selects,
i.e
if we have a file with
1/1/1970 Sam 1934.344
...

and the client calls the function like this.
vector<string> ss = get_data<string>(file_path, 1, 's'); then the
function should put all the dates in the first column in a
vector<string> and return that. or a vector of all the numbers in the
third column in case of
vector<double> ii = get_data<double>(file_path, 3, 'i');

Maybe the following contains some ideas you can use:
[snip]

data.txt:
2006/12/05 Sam 3.4
2007/01/12 Bert 2.718282

output:
Sam
Bert

Here is a variation of the code that actually has a function returning the
vector you want:


#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>


struct line_data {

std::string date;
std::string name;
double d;

}; // line_data

std::eek:stream & operator<< ( std::eek:stream & o_str,
line_data const & l ) {
o_str << l.date
<< " "
<< l.name
<< " "
<< l.d
<< "\n";
return ( o_str );
}

std::istream & operator>> ( std::istream & i_str,
line_data & l ) {
line_data dummy;
i_str >> dummy.date;
i_str >> dummy.name;
i_str >> dummy.d;
if ( i_str ) {
l = dummy;
}
return ( i_str );
}


std::string get_data ( line_data const & l ) {
return ( l.date );
}

std::string get_name ( line_data const & l ) {
return ( l.name );
}

double get_d ( line_data const & l ) {
return ( l.d );
}

template < typename T >
struct getter_traits;

template < typename T >
struct getter_traits< T(*)(line_data const &) > {

typedef T result_type;

};


template < typename T >
std::vector< typename getter_traits<T>::result_type >
get_vector ( std::istream & i_str, T getter ) {
std::vector< typename getter_traits<T>::result_type > result;
std::transform( std::istream_iterator< line_data >( i_str ),
std::istream_iterator< line_data >(),
std::back_inserter( result ),
getter );
return ( result );
}

int main ( void ) {
std::ifstream file ( "data.txt" );
std::vector< std::string > name_vector
= get_vector( file, get_name );

std::copy( name_vector.begin(), name_vector.end(),
std::eek:stream_iterator< std::string >( std::cout, "\n" ) );
}


Best

Kai-Uwe Bux

thanks a lot
I will have to chew on this for a some time.
if the file changes, say the column numbers, data types, delimiting
char, or even a mistake in the size of the space between a cell and
another, this code will have to be modified every time.

the activity of reading column-data from file into a specific type is
soooo common. isn't there a method or lib that are there for that?
 
L

Larry I Smith

Gary said:
Hi

I wrote this routine below but getting the error below it which I
don't know how to fix.

thanks


//useful.h
/**
Reads data from file into a given type vector.
@param string full path to file containing the data
@param short int column number to return in a vector
@param char type of data s-string, d-double, i-int
...
@return vector<type_selected_as_above>
*/
template<class T>
vector<T> get_data(string, short, char);

****************************************************************
//useful.cpp

template<class T> vector<T> get_data(string s,
short sh,
char ch){
sh--;
ifstream in(s.c_str());
string line;
vector<string> vs;
vector<double> vd;
vector<int> vi;
while( getline(in, line) ){
stringstream input(line.c_str());
int j = 0;
switch (ch){
case 's':
string st;
while( input >> st)
if(sh == j++) vs.push_back(st);
case 'd':
double dt;
while( input >> dt)
if(sh == j++) vd.push_back(dt);
case 'i':
int it;
while( input >> it)
if(sh == j++) vi.push_back(it);
default:
cout << "type not known" << endl;
}
}
switch(ch){
case 's':return vs;
case 'd':return vd;
case 'i':return vi;
}
}
****************************************************************
int main(){
string f = "/data/home/activity.dat";
vector<string> vss = get_data(f, 1, 's'); //line 40 error


typedef vector<string>::iterator ITER;
ITER iterEnd = vss.end();
for (ITER iter = vss.begin(); iter != iterEnd; ++iter)
copy(iter->begin(), iter->end(), ostream_iterator<string>(cout, endl));


****************************************************************
main.cpp:40: error: no matching function for call to
'get_data(std::string&, int, char)'

main.cpp:46: error: no matching function for call to
'std::eek:stream_iterator<std::basic_string<char, std::char_traits<char>,


Below is one way to do it. It needs error checking added...

----- file 'activity.dat':

1/1/1970 Sam 1934.344 27
8/21/48 larry 100.234 999
06/15/1967 nancy 1234567.89 100000

----- file 'gary.cpp':

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>

typedef std::vector< std::string > VectStr;
typedef std::vector< double > VectDbl;
typedef std::vector< int > VectInt;

// print the vector 'vt'
template < typename T >
int printVect( std::vector< T >& vt )
{
typename std::vector< T >::iterator it;

for (it = vt.begin(); it != vt.end(); ++it)
std::cout << *it << std::endl;
}

// read the data from column number 'col' (one based)
// of file 'fname' into the vector 'vt'.
// all lines in the file must have the same column layout.
template< typename T >
int getData( std::string& fname, int col, std::vector< T >& vt )
{
std::ifstream in( fname.c_str() );
std::string line;

T tok;

while( std::getline( in, line ) )
{
std::string junk;

std::stringstream input( line.c_str() );

for( int j = 1; j < col; ++j )
input >> junk;

input >> tok;
vt.push_back( tok );

line.erase();
}

return 0;
}

int main()
{
std::string f = "activity.dat";

VectStr vs; // a vector of strings
VectDbl vd; // a vector of doubles
VectInt vi; // a vector of ints

// read and print the strings from column ONE
// of the file named by 'f'.
getData( f, 1, vs );
printVect(vs);

// read and print the strings from column TWO
// of the file named by 'f'.
vs.clear(); // delete any current data in 'vs'
getData( f, 2, vs );
printVect(vs);

// read and print the doubles from column THREE
// of the file named by 'f'.
getData( f, 3, vd );
printVect(vd);

// read and print the ints from column FOUR
// of the file named by 'f'.
getData( f, 4, vi );
printVect(vi);

return 0;
}
 
L

Larry I Smith

Gary said:
Kai-Uwe Bux said:
Kai-Uwe Bux said:
Gary Wessle wrote:

[snip]
What is the underlying problem that you are trying to solve. It looks as
though you are making things way more complicated than they should be.

I am trying to return a vector of whatever type the client selects,
i.e
if we have a file with
1/1/1970 Sam 1934.344
...

and the client calls the function like this.
vector<string> ss = get_data<string>(file_path, 1, 's'); then the
function should put all the dates in the first column in a
vector<string> and return that. or a vector of all the numbers in the
third column in case of
vector<double> ii = get_data<double>(file_path, 3, 'i');
Maybe the following contains some ideas you can use:
[snip]

data.txt:
2006/12/05 Sam 3.4
2007/01/12 Bert 2.718282

output:
Sam
Bert
Here is a variation of the code that actually has a function returning the
vector you want:


#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>


struct line_data {

std::string date;
std::string name;
double d;

}; // line_data

std::eek:stream & operator<< ( std::eek:stream & o_str,
line_data const & l ) {
o_str << l.date
<< " "
<< l.name
<< " "
<< l.d
<< "\n";
return ( o_str );
}

std::istream & operator>> ( std::istream & i_str,
line_data & l ) {
line_data dummy;
i_str >> dummy.date;
i_str >> dummy.name;
i_str >> dummy.d;
if ( i_str ) {
l = dummy;
}
return ( i_str );
}


std::string get_data ( line_data const & l ) {
return ( l.date );
}

std::string get_name ( line_data const & l ) {
return ( l.name );
}

double get_d ( line_data const & l ) {
return ( l.d );
}

template < typename T >
struct getter_traits;

template < typename T >
struct getter_traits< T(*)(line_data const &) > {

typedef T result_type;

};


template < typename T >
std::vector< typename getter_traits<T>::result_type >
get_vector ( std::istream & i_str, T getter ) {
std::vector< typename getter_traits<T>::result_type > result;
std::transform( std::istream_iterator< line_data >( i_str ),
std::istream_iterator< line_data >(),
std::back_inserter( result ),
getter );
return ( result );
}

int main ( void ) {
std::ifstream file ( "data.txt" );
std::vector< std::string > name_vector
= get_vector( file, get_name );

std::copy( name_vector.begin(), name_vector.end(),
std::eek:stream_iterator< std::string >( std::cout, "\n" ) );
}


Best

Kai-Uwe Bux

thanks a lot
I will have to chew on this for a some time.
if the file changes, say the column numbers, data types, delimiting
char, or even a mistake in the size of the space between a cell and
another, this code will have to be modified every time.

the activity of reading column-data from file into a specific type is
soooo common. isn't there a method or lib that are there for that?

Well, it's not really very common.
Most apps that write data to a file, then read it back later,
are specifically coded to understand the file layout.
For general data transmission/storage in a platform-portable
manner, XML is often used. Another comman variant is the
old 'key = value' syntax.

See my earlier reply to your original message for a simple
example program that does what you said you wanted.

Regards,
Larry
 
G

Gary Wessle

Larry I Smith said:
Below is one way to do it. It needs error checking added...

----- file 'activity.dat':

1/1/1970 Sam 1934.344 27
8/21/48 larry 100.234 999
06/15/1967 nancy 1234567.89 100000

----- file 'gary.cpp':

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>

typedef std::vector< std::string > VectStr;
typedef std::vector< double > VectDbl;
typedef std::vector< int > VectInt;

// print the vector 'vt'
template < typename T >
int printVect( std::vector< T >& vt )
{
typename std::vector< T >::iterator it;

for (it = vt.begin(); it != vt.end(); ++it)
std::cout << *it << std::endl;
}

// read the data from column number 'col' (one based)
// of file 'fname' into the vector 'vt'.
// all lines in the file must have the same column layout.
template< typename T >
int getData( std::string& fname, int col, std::vector< T >& vt )
{
std::ifstream in( fname.c_str() );
std::string line;

T tok;

while( std::getline( in, line ) )
{
std::string junk;

std::stringstream input( line.c_str() );

for( int j = 1; j < col; ++j )
input >> junk;

input >> tok;
vt.push_back( tok );

line.erase();
}

return 0;
}

int main()
{
std::string f = "activity.dat";

VectStr vs; // a vector of strings
VectDbl vd; // a vector of doubles
VectInt vi; // a vector of ints

// read and print the strings from column ONE
// of the file named by 'f'.
getData( f, 1, vs );
printVect(vs);

// read and print the strings from column TWO
// of the file named by 'f'.
vs.clear(); // delete any current data in 'vs'
getData( f, 2, vs );
printVect(vs);

// read and print the doubles from column THREE
// of the file named by 'f'.
getData( f, 3, vd );
printVect(vd);

// read and print the ints from column FOUR
// of the file named by 'f'.
getData( f, 4, vi );
printVect(vi);

return 0;
}

thank you

I am getting the errors undefined references to get_data and
print_vect when linking the files below. the complete error is at the
bottom of the post.

I placed the declarations below in a useful.h file

****************************************************************
#ifndef USEFUL_H
#define USEFUL_H
#include <vector>
using std::vector;
#include <string>
using std::string;


// print a vector
template < typename T >
int print_vect( vector< T >& );

//read data from file into a vector of type T
template< typename T >
int get_data( string&, int, vector< T >&);

#endif

then the definition file useful.cpp
****************************************************************
#include <string>
using std::string;
#include<vector>
using std::vector;
#include <fstream>
using std::ifstream;
#include <sstream>
using std::stringstream;
using std::eek:stringstream;
#include<iostream>
using std::cout;
using std::endl;

#include "useful.h"

// print the vector 'vt'
template < typename T >
int print_vect( vector< T >& vt )
{
typename vector< T >::iterator it;

for (it = vt.begin(); it != vt.end(); ++it)
cout << *it << endl;
}

// read the data from column number 'col' (one based)
// of file 'fname' into the vector 'vt'.
// all lines in the file must have the same column layout.
template< typename T >
int get_data( string& fname, int col, vector< T >& vt )
{
ifstream in( fname.c_str() );
string line;

T tok;

while( getline( in, line ) )
{
string junk;
stringstream input( line.c_str() );
for( int j = 1; j < col; ++j )
input >> junk;
input >> tok;
vt.push_back( tok );
line.erase();
}
return 0;
}


and the testing file main.cpp
****************************************************************
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <algorithm>
#include <iterator>
using std::eek:stream_iterator;

#include "useful.h"



int main() {

string f = "../data/fix_spread/audusd";
vector<string> vs;

get_data( f, 1, vs );
print_vect(vs);
}

**************** error ****************
cd /home/fred/myPrograms/backtest/useful/
make -k
g++ -gdwarf-2 -c -o main.o main.cpp
g++ -Wall -gdwarf-2 -o proj main.o useful.o
main.o: In function `main':
/home/fred/myPrograms/useful/main.cpp:40: undefined reference
to `int get_data<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, int,
std::vector<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > >&)'

/home/fred/myPrograms/useful/main.cpp:41: undefined reference
to `int print_vect<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >(std::vector<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >,
std::allocator<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > > >&)'

collect2: ld returned 1 exit status
make: *** [proj] Error 1
 
L

Larry I Smith

Gary said:
Larry I Smith said:
Below is one way to do it. It needs error checking added...

----- file 'activity.dat':

1/1/1970 Sam 1934.344 27
8/21/48 larry 100.234 999
06/15/1967 nancy 1234567.89 100000

----- file 'gary.cpp':

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>

typedef std::vector< std::string > VectStr;
typedef std::vector< double > VectDbl;
typedef std::vector< int > VectInt;

// print the vector 'vt'
template < typename T >
int printVect( std::vector< T >& vt )
{
typename std::vector< T >::iterator it;

for (it = vt.begin(); it != vt.end(); ++it)
std::cout << *it << std::endl;
}

// read the data from column number 'col' (one based)
// of file 'fname' into the vector 'vt'.
// all lines in the file must have the same column layout.
template< typename T >
int getData( std::string& fname, int col, std::vector< T >& vt )
{
std::ifstream in( fname.c_str() );
std::string line;

T tok;

while( std::getline( in, line ) )
{
std::string junk;

std::stringstream input( line.c_str() );

for( int j = 1; j < col; ++j )
input >> junk;

input >> tok;
vt.push_back( tok );

line.erase();
}

return 0;
}

int main()
{
std::string f = "activity.dat";

VectStr vs; // a vector of strings
VectDbl vd; // a vector of doubles
VectInt vi; // a vector of ints

// read and print the strings from column ONE
// of the file named by 'f'.
getData( f, 1, vs );
printVect(vs);

// read and print the strings from column TWO
// of the file named by 'f'.
vs.clear(); // delete any current data in 'vs'
getData( f, 2, vs );
printVect(vs);

// read and print the doubles from column THREE
// of the file named by 'f'.
getData( f, 3, vd );
printVect(vd);

// read and print the ints from column FOUR
// of the file named by 'f'.
getData( f, 4, vi );
printVect(vi);

return 0;
}

thank you

I am getting the errors undefined references to get_data and
print_vect when linking the files below. the complete error is at the
bottom of the post.

I placed the declarations below in a useful.h file

****************************************************************
#ifndef USEFUL_H
#define USEFUL_H
#include <vector>
using std::vector;
#include <string>
using std::string;


// print a vector
template < typename T >
int print_vect( vector< T >& );

//read data from file into a vector of type T
template< typename T >
int get_data( string&, int, vector< T >&);

#endif

then the definition file useful.cpp
****************************************************************
#include <string>
using std::string;
#include<vector>
using std::vector;
#include <fstream>
using std::ifstream;
#include <sstream>
using std::stringstream;
using std::eek:stringstream;
#include<iostream>
using std::cout;
using std::endl;

#include "useful.h"

// print the vector 'vt'
template < typename T >
int print_vect( vector< T >& vt )
{
typename vector< T >::iterator it;

for (it = vt.begin(); it != vt.end(); ++it)
cout << *it << endl;
}

// read the data from column number 'col' (one based)
// of file 'fname' into the vector 'vt'.
// all lines in the file must have the same column layout.
template< typename T >
int get_data( string& fname, int col, vector< T >& vt )
{
ifstream in( fname.c_str() );
string line;

T tok;

while( getline( in, line ) )
{
string junk;
stringstream input( line.c_str() );
for( int j = 1; j < col; ++j )
input >> junk;
input >> tok;
vt.push_back( tok );
line.erase();
}
return 0;
}


and the testing file main.cpp
****************************************************************
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <algorithm>
#include <iterator>
using std::eek:stream_iterator;

#include "useful.h"



int main() {

string f = "../data/fix_spread/audusd";
vector<string> vs;

get_data( f, 1, vs );
print_vect(vs);
}

**************** error ****************
cd /home/fred/myPrograms/backtest/useful/
make -k
g++ -gdwarf-2 -c -o main.o main.cpp
g++ -Wall -gdwarf-2 -o proj main.o useful.o
main.o: In function `main':
/home/fred/myPrograms/useful/main.cpp:40: undefined reference
to `int get_data<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >(std::basic_string<char,
std::char_traits<char>, std::allocator<char> >&, int,
std::vector<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > >&)'

/home/fred/myPrograms/useful/main.cpp:41: undefined reference
to `int print_vect<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > >(std::vector<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >,
std::allocator<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > > >&)'

collect2: ld returned 1 exit status
make: *** [proj] Error 1

Did my ORIGINAL code in 'gary.cpp' work as you expected?

This is basic C++, all of the sample code was in one file
for a reason...

The templates must be visible where they are used, eg: in main().
You can not define (yet not instantiate) templates in one object
file then try to use them in another.

Your file 'useful.cpp' serves no purpose. The template def's are
there, but no template instances. Then in 'main.cpp' you try
to use templates (get_data, & print_vect) that are not defined
in 'main.cpp'.

If you MUST use seperate files, try something
along these lines:

----- file 'useful.hpp':

#ifndef USEFUL_HPP
#define USEFUL_HPP

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>

typedef std::vector< std::string > VectStr;
typedef std::vector< double > VectDbl;
typedef std::vector< int > VectInt;

// print the vector 'vt'
template < typename T >
int printVect( std::vector< T >& vt )
{
typename std::vector< T >::iterator it;

for (it = vt.begin(); it != vt.end(); ++it)
std::cout << *it << std::endl;
}

// read the data from column number 'col' (one based)
// of file 'fname' into the vector 'vt'.
// all lines in the file must have the same column layout.
template< typename T >
int getData( std::string& fname, int col, std::vector< T >& vt )
{
std::ifstream in( fname.c_str() );
std::string line;

T tok;

while( std::getline( in, line ) )
{
std::string junk;

std::stringstream input( line.c_str() );

for( int j = 1; j < col; ++j )
input >> junk;

input >> tok;
vt.push_back( tok );

line.erase();
}

return 0;
}

#endif

----- file 'main.cpp':

#include "useful.hpp"

int main()
{
std::string f = "../data/fix_spread/audusd";
std::vector< std::string > vs;

getData( f, 1, vs );
printVect( vs );

return 0;
}


Compile the program 'proj' from 'main.cpp':

g++ -o proj main.cpp

Run the program 'proj':

./proj

Larry
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Crossword 2
Filter sober in c++ don't pass test 0
My Status, Ciphertext 2
Crossword 14
TF-IDF 1
Fibonacci 0
printing vectors 4
Can someone tell me what's wrong with this question on StackOverflow? 0

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top