Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Ошибка при использовании template <class T>


Автор: Voldemar2004 25.9.2008, 10:54
Сделал класс SelectTable. Метод ReadFileToArray() - открывает текстовый файл и считывает в 
Код
unsigned long int *array
 целые числа.  Далее с помощью метода 
Код
My.ReturnElementByIndex<unsigned long int>(2, My.ReturnFirstOfArray() );
 - вывожу например 2-ой элемент массива. С этим нет проблем. 

Но когда использую тип std::string в методе 
Код
ReturnElementByIndex()
:

Код
My.ReadFileName("C:\\Name.txt");
My.ReturnElementByIndex<std::string>(0, My.ReturnFirstOfFName() );


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

Код
// Метод возвращает элемент массива *array по индексу.
        template <class T> SelectTable::ReturnElementByIndex(unsigned long int index, T *UserArray) {
                if (index>=0 && index<n) { return UserArray[index]; }
                else return -1;
        }


в строке 

Код
                if (index>=0 && index<n) { return UserArray[index]; }
 "нельзя конвертировать STL::string в int".


Код
//---------------------------------------------------------------------------

#include <fstream>      // Потоковый ввод-вывод в файл, std::ifstream File(FileName);
#include <string>       // std::string *array

//---------------------------------------------------------------------------

class SelectTable {

private:
        // Метод подсчета количества строк в файле.
        signed long int StringCount (char* FileName);

        unsigned long int *array;

        unsigned long int n;

        std::string *FName;

public:

        // Конструктор класса.
        SelectTable (void);

        // Деструктор класса.
        ~SelectTable (void);

        // Конструктор копирования.
        SelectTable(const SelectTable &T);

        // Метод считывает весь файл в массив.
        void ReadFileToArray(char* FileName);

        // Метод возвращает элемент массива *array по индексу.
        template <class T> ReturnElementByIndex(unsigned long int index, T *UserArray);

        // Метод считывает в массив типа std::string* имена файлов,
        void ReadFileName(char* FileName);

        // Возвращает 1-ый элемент массива *array.
        unsigned long int *ReturnFirstOfArray();

        // Возвращает 1-ый элемент массива *FName.
        std::string *SelectTable::ReturnFirstOfFName();

};

//---------------------------------------------------------------------------

        // Метод подсчета количества строк в файле.
        // Функция возвращает знаковый целый тип:
        // -1 - в случае ошибки открытия файла,
        // или количество строк в файле.
        signed long int SelectTable::StringCount (char* FileName) {

        std::string str;

        // Переменная для хранения количества строк.
        signed long int String_Counter = 0;

        // Чтение файла.
        std::ifstream File(FileName);

        // Вовзратить -1, если ошибка чтения файла.
        if( File.fail() ) return -1;

            while( !File.eof() )
            {
             getline(File, str);
             String_Counter++;
            };

        return String_Counter;

        }

//---------------------------------------------------------------------------

        // Конструктор класса.
        SelectTable::SelectTable(void):n(0), array(NULL), FName(NULL)
        {
        }

//---------------------------------------------------------------------------

        // Деструктор класса.
        SelectTable::~SelectTable(void)
        {
        if(n) delete []array;
        if(FName) delete []FName;
        }

//---------------------------------------------------------------------------

        // Конструктор копирования.
        SelectTable::SelectTable(const SelectTable &T) {

                if(T.array){
                array = new unsigned long int [T.n];
                n = T.n;
                FName = T.FName;
                }
        }

//---------------------------------------------------------------------------

        // Метод считывает файл в массив типа unsigned long int* .
        void SelectTable::ReadFileToArray(char* FileName){

                // Если в файле есть хотя бы одна строка,
                // то выделить память.
                if (StringCount(FileName) > 0) {
                n=StringCount(FileName);
                array = new unsigned long int [n];
                
                        std::string str;
                        // Чтение файла
                        std::ifstream File(FileName);

                        unsigned long int i=0;

                        // Пока нет конца файла.
                        while( !File.eof() )
                        {
                                getline(File, str);
                                array[i++] = atol( str.c_str() );
                        };
                }
        }

//---------------------------------------------------------------------------

        // Метод возвращает элемент массива *array по индексу.
        template <class T> SelectTable::ReturnElementByIndex(unsigned long int index, T *UserArray) {
                if (index>=0 && index<n) { return UserArray[index]; }
                else return -1;
        }

//---------------------------------------------------------------------------

        // Метод считывает в массив типа std::string* имена файлов,
        void SelectTable::ReadFileName(char* FileName){

        std::string str;

        std::ifstream File(FileName);

                if( !File.fail() )
                {
                FName = new std::string [ StringCount(FileName) ];

                unsigned long int i=0;

                    while( !File.eof() )
                    {
                     getline(File, str);
                     FName[i++] = str;
                    };

                }
        }

//---------------------------------------------------------------------------

        // Возвращает 1-ый элемент массива *array.

        unsigned long int *SelectTable::ReturnFirstOfArray() {
        return array;
        }

//---------------------------------------------------------------------------

        // Возвращает 1-ый элемент массива *FName.

        std::string *SelectTable::ReturnFirstOfFName() {
        return FName;
        }

//---------------------------------------------------------------------------

int main() {

SelectTable My;

// Нормально работает:

My.ReadFileToArray("C:\\1.txt");
ShowMessage( My.ReturnElementByIndex<unsigned long int>(0, My.ReturnFirstOfArray() ) );


My.ReadFileName("C:\\Name.txt");
ShowMessage( My.ReturnElementByIndex<std::string>(0, My.ReturnFirstOfFName() ) );


return 0;

}
//---------------------------------------------------------------------------




Добавлено через 3 минуты и 28 секунд
В чем ошибка ?

Автор: vinick 25.9.2008, 11:35
Код

// Метод возвращает элемент массива *array по индексу.
        template <class T> SelectTable::ReturnElementByIndex(unsigned long int index, T *UserArray) {
                if (index>=0 && index<n) { return UserArray[index]; }
                else return -1;
        }


Тип возвращаемого значения кто указывать будет? Современные компиляторы такое не пропустят, а вот некоторые старые могут решить, что по умолчанию возвращается int. Ну и вобще, у тебя получается одна и та же специализация функции может возвращать два значения - в одном случае тип Т (return UserArray[index]), а во втором случае int (return -1). Так делать нельзя.

Код

template <class T> 
Т SelectTable::ReturnElementByIndex(unsigned long int index, T *UserArray) {
                if (index>=0 && index<n) { return UserArray[index]; }
                else throw std::out_of_range();
        }


Автор: Voldemar2004 25.9.2008, 12:15
vinick, спасибо, помогло. smile 
Код

        template <class T> T SelectTable::ReturnElementByIndex(unsigned long int index, T *UserArray) {
                if (index>=0 && index<n) { return UserArray[index]; }
                else throw std::out_of_range();
        }


теперь ругается на 
Код
else throw std::out_of_range();
 Could not find a match for 'STL::out_of_range::out_of_range()

компилятор выдает ворнинги: Function should return a value на метод ReturnElementByIndex(). Хотя значения возвращаются ? smile

Добавлено через 2 минуты и 15 секунд
Цитата(vinick @  25.9.2008,  12:35 Найти цитируемый пост)
у тебя получается одна и та же специализация функции может возвращать два значения - в одном случае тип Т (return UserArray[index]), а во втором случае int (return -1). Так делать нельзя.
Об этом я тоже хотел спросить, знал, что делал не правильно, и не знал про 
Код
throw std::out_of_range();


Автор: Alek86 25.9.2008, 12:32
Цитата(Voldemar2004 @  25.9.2008,  12:15 Найти цитируемый пост)
Хотя значения возвращаются ? 

при throw не возвращаются
если ворнинг не нравится. напиши так
Код
template <class T> T SelectTable::ReturnElementByIndex(unsigned long int index, T *UserArray) {
                if (!(index>=0 && index<n))
                     throw std::out_of_range();
                 return UserArray[index];                
        }

Автор: vinick 25.9.2008, 12:49
Цитата(Voldemar2004 @  25.9.2008,  12:15 Найти цитируемый пост)

 Could not find a match for 'STL::out_of_range::out_of_range()


Ошибся, там надо строку с сообщением указывать.
например
Код

#include <stdexcept>
...
throw std::out_of_range("bad index");

Автор: Voldemar2004 25.9.2008, 21:09
Всем спасибо за помощь.Вот этот код:
Код
template <class T> T SelectTable::ReturnElementByIndex(unsigned long int index, T *UserArray) {
                if (!(index>=0 && index<n))
                     throw std::out_of_range();
                 return UserArray[index];                
        }


разве не тоже самое, что и:
Код
template <class T> T SelectTable::ReturnElementByIndex(unsigned long int index, T *UserArray) {
                if (index>=0 && index<n)
                 return UserArray[index];    
                throw std::out_of_range();            
        }
 ?


Автор: UnrealMan 26.9.2008, 01:41
Цитата(Voldemar2004 @  25.9.2008,  13:15 Найти цитируемый пост)
компилятор выдает ворнинги: Function should return a value на метод ReturnElementByIndex(). Хотя значения возвращаются ?

Что за рухлядь ты используешь в качестве компилятора?

Автор: Voldemar2004 26.9.2008, 09:40
Цитата(UnrealMan @  26.9.2008,  02:41 Найти цитируемый пост)
Что за рухлядь ты используешь в качестве компилятора?
Borland C++ 5.02, C++ Builder 6.0, MinGW Developer Studio.

Автор: vinter 26.9.2008, 09:53
UnrealMan, а что не так? VS на это бы написала, что не на все пути есть return..

Автор: Alek86 26.9.2008, 09:56
Цитата(Voldemar2004 @  25.9.2008,  21:09 Найти цитируемый пост)
разве не тоже самое, что и:

в моем коде не должно быть ворнинга
это чисто изменение для компилятора

Автор: Voldemar2004 26.9.2008, 10:58
Цитата(Alek86 @  26.9.2008,  10:56 Найти цитируемый пост)
в моем коде не должно быть ворнингаэто чисто изменение для компилятора
Ворнинги остались.

Имхо, такое изменение кода, есть тоже самое, что и:

Код

если 10 > 5
 тогда "Да"
иначе "Нет"


Код

если не(10 > 5)
 тогда "Нет"          
иначе "Да"





Автор: Hroft 26.9.2008, 11:47
Как это остались? Безусловный ретурн последней строкой метода, какой может быть еще ворнинг?

Цитата(Voldemar2004 @  26.9.2008,  10:58 Найти цитируемый пост)
если не(10 > 5)
 тогда "Нет"          
иначе "Да"

Нет, слова "иначе" нету. Ответ "Да" всегда, когда не "Нет", а не только тогда, когда не "Нет" smile Семантика одна, а запись разная, компилятор же на запись смотрит, а не на семантику.
Такая же техника может использоваться, если нужно кинуть исключение посреди рабочего кода в Java. Если просто написать throw, то компилятор ругнется на последующие инструкции как unreachable, но если написать if (true) throw, он, хотя и нахмурится на всегда выполняющееся условие, тем не менее скомпилирует.

Автор: UnrealMan 26.9.2008, 14:43
Цитата(vinter @  26.9.2008,  10:53 Найти цитируемый пост)
UnrealMan, а что не так?

Насколько я помню, даже у VC++6.0 не было такого бреда с диагностикой. throw без соответствующего обработчика в пределах функции всегда заменяет return, а потому предупреждений такого рода в вышеприведённом коде быть не должно.

Цитата(vinter @  26.9.2008,  10:53 Найти цитируемый пост)
VS на это бы написала, что не на все пути есть return.. 

VC++8.0 ничего не пишет.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)