C++ newbie: template function problem--getting string and numerical data from text file, putting it in vector
I am a newbie. I have tried to write a template function that gets string AND numerical data (for example, douubles) from a text file, then puts it in a vector. Each element of the vector is a different name or number.
Last week I asked whether overloading or a template might be best for this. I would like to go with a template method, where the results vector (what I want) is passed to the function to provide the template parameter T. But I'm having problems. If anyone could help, I would be grateful! The code is below, followed by the error I'm getting.
// My开发者_如何学Go code:
template<typename T>
void readFile( const std::string& name, const std::string& find, std::vector<T>& results ){
std::ifstream file( name.c_str( ) );
std::string line;
while( std::getline( file, line ) )
{
if( line == find )
{
std::getline( file, line );
line.erase(remove( line.begin(), line.end(), '\'' ), line.end() );
std::istringstream streamLine( line );
results = std::vector<T>( std::istream_iterator<T>(streamLine), std::istream_iterator<T>() );
}
}
}
Call in main():
readFile( name, "label", results );
The error I'm getting is below. I don't understand how the function call doesn't match the definition. Apologies in advance for any dumb mistakes!
error: no matching function for call 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> > > >
::resize(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
The weird thing is that if I make the function return the vector "result" instead of void, then things seem to work. Here's what I mean:
std::vector<T> readFile( const std::string& name, const std::string& find, std::vector<T>& results )
with a return statement in the function definition of:
return std::vector<T>( std::istream_iterator<T>(streamLine), std::istream_iterator<T>() );
But it seems clunky/bad style to do it this way. I would have thought that using references would be better. Even if it isn't better, I'm curious to know why the first method (with void) doesn't work.
Any tips would be appreciated!
I had to do a bunch of work to make this a fully compilable code snippet. Here is what I came up with:
#include <string>
#include <vector>
#include <istream>
#include <fstream>
#include <iterator>
#include <sstream>
#include <algorithm>
template<typename T>
void readFile(const std::string& name,
const std::string& find,
std::vector<T>& results )
{
std::ifstream file( name.c_str( ) );
std::string line;
while( std::getline( file, line ) )
{
if( line == find )
{
std::getline( file, line );
line.erase(remove( line.begin(), line.end(), '\'' ), line.end() );
std::istringstream streamLine( line );
results = std::vector<T>( std::istream_iterator<T>(streamLine),
std::istream_iterator<T>() );
}
}
}
void do_it_with_strings(std::vector<std::string> &results)
{
readFile("fred", "barney", results);
}
This code snippet compiles just fine with gcc 4.5.1. What are the exact types of name
and results
in your main
function? Also, the problem seems to be calling the vector's resize
function. You don't appear to be doing that directly in your code, though it's possible the vector constructor or assignment operator does it internally.
But regardless, I wouldn't suggest you write your code that way anyway. I would suggest you do this instead:
#include <string>
#include <vector>
#include <istream>
#include <fstream>
#include <iterator>
#include <sstream>
#include <algorithm>
template<typename T>
std::vector<T> readFile(const std::string& name, const std::string& find )
{
std::ifstream file( name.c_str( ) );
std::string line;
while( std::getline( file, line ) )
{
if( line == find )
{
std::getline( file, line );
line.erase(remove( line.begin(), line.end(), '\'' ), line.end() );
std::istringstream streamLine( line );
return std::vector<T>( std::istream_iterator<T>(streamLine),
std::istream_iterator<T>() );
}
}
return std::vector<T>();
}
void do_it_with_strings(std::vector<std::string> &results)
{
results = readFile<std::string>("fred", "barney");
}
In a function like this, I think it's better to be explicitly stating the type you're expecting to read when you call the function rather than have it implicitly determined from the type of the vector
you pass in.
Here is a piece of code which will get you either strings or numerical values from a file:
#include <fstream>
#include <vector>
#include <iterator>
#include <algorithm>
template<typename T>
void read_values(const std::string& filename, std::vector<T>& coll)
{
std::fstream file(filename);
std::copy (std::istream_iterator<T>(file),
std::istream_iterator<T>(),
back_inserter(coll));
std::sort(coll.begin(), coll.end());
coll.erase(std::unique(coll.begin(), coll.end()), coll.end());
}
int main(int argc, char* argv[])
{
std::vector<int> values;
read_values("C:\\example.txt", values);
return 0;
}
If you wish to read string values instead, you just need to provide a std::vector of std::string to pass into the template function.
精彩评论