C ++ newbie: проблема с функцией шаблона - получение строковых и числовых данных из текстового файла, размещение их в векторе - PullRequest
0 голосов
/ 07 февраля 2011

Я новичок. Я попытался написать шаблонную функцию, которая получает строку И числовые данные (например, douubles) из текстового файла, а затем помещает его в вектор. Каждый элемент вектора имеет другое имя или номер.

На прошлой неделе я спросил, лучше ли для этого перегрузка или шаблон. Я хотел бы пойти с методом шаблона, где вектор результатов (что я хочу) передается в функцию, чтобы обеспечить параметр шаблона T. Но у меня есть проблемы. Если бы кто-нибудь мог помочь, я был бы благодарен! Код ниже, сопровождаемый ошибкой, которую я получаю.

// Мой код:

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

Позвонить на главную ():

readFile( name, "label", results );

Ошибка, которую я получаю, ниже. Я не понимаю, как вызов функции не соответствует определению. Заранее извиняюсь за любые глупые ошибки!

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> >&)'

Странная вещь в том, что если я заставлю функцию возвращать вектор «результат» вместо void, то все будет работать. Вот что я имею в виду:

std::vector<T> readFile( const std::string& name, const std::string& find, std::vector<T>& results )

с оператором возврата в определении функции:

return std::vector<T>( std::istream_iterator<T>(streamLine), std::istream_iterator<T>() );

Но это кажется неуклюжим / плохим стилем сделать это таким образом. Я бы подумал, что использование ссылок будет лучше. Даже если это не лучше, мне любопытно узнать, почему первый метод (с void) не работает.

Любые советы приветствуются!

Ответы [ 2 ]

1 голос
/ 07 февраля 2011

Вот фрагмент кода, который будет получать строки или числовые значения из файла:

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

Если вы хотите вместо этого прочитать строковые значения, вам просто нужно предоставить std :: vectorstd :: string для передачи в функцию шаблона.

1 голос
/ 07 февраля 2011

Мне пришлось проделать кучу работы, чтобы сделать этот код полностью компилируемым.Вот что я придумал:

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

Этот фрагмент кода прекрасно компилируется с gcc 4.5.1.Каковы точные типы name и results в вашей функции main?Кроме того, проблема, кажется, вызывает функцию вектора resize.Похоже, вы не делаете это непосредственно в своем коде, хотя вполне возможно, что векторный конструктор или оператор присваивания делают это внутренне.

Но, тем не менее, я бы не советовал вам так или иначе писать свой код.Я бы посоветовал вам сделать это вместо этого:

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

В такой функции я думаю, что лучше явно указывать тип, который вы ожидаете прочитать, когда вызываете функцию, а не определять ее неявным образомот типа vector, который вы передаете.

...