Итераторы и перегрузка << Оператор - PullRequest
3 голосов
/ 03 августа 2011

Я усек этот пост.Первоначальный пост ушел, чтобы облегчить чтение.Соответствующие части и проблемы все еще существуют.


ОБНОВЛЕНИЕ

Ошибка, которую меня попросили опубликовать:

[mehoggan@desktop qsort]$ g++ -o qsort -Wall main.cpp
/tmp/ccuAUzlh.o: In function `Sorters::QuickSorter<float>::test_and_sort(float*, int)':
main.cpp:(.text._ZN7Sorters11QuickSorterIfE13test_and_sortEPfi[Sorters::QuickSorter<float>::test_and_sort(float*, int)]+0x61): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& Sorters::operator<< <float>(std::basic_ostream<char, std::char_traits<char> >&, Sorters::Sorter<float>&)'
collect2: ld returned 1 exit status
[mehoggan@desktop qsort]$ 

икоторый использует следующий код:

#ifndef SORTERS_H_
#define SORTERS_H_
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cmath>
#include <ctime>
#include <assert.h>

using std::vector;
using std::cin;
using std::cout;
using std::endl;
using std::ostream_iterator;
using std::istream_iterator;
using std::next_permutation;
using std::back_inserter;
using std::ostream;

namespace Sorters {
    template<typename T>
    class Sorter {
        public:
            Sorter( ) { };
            virtual ~Sorter( ) { };
            virtual void test_and_sort( T *data, int size )=0;
        protected:
            virtual void sort( typename vector<T>::iterator left, typename vector<T>::iterator right )=0;
            vector<T> m_data;
    };

    template<typename T>
    class QuickSorter : public Sorter<T> {
        public:
            QuickSorter( ) { };
            virtual ~QuickSorter( ) { };
            virtual void test_and_sort( T *data, int size );
        private:
            virtual void sort( typename std::vector<T>::iterator left, typename std::vector<T>::iterator right );
            template<typename S> friend ostream& operator<< ( ostream &stream, Sorter<S> &sorter );
    };
}

template<typename T>
void Sorters::QuickSorter<T>::sort( typename vector<T>::iterator left, typename vector<T>::iterator right ) {

}

template<typename T>
void Sorters::QuickSorter<T>::test_and_sort( T *data, int size ) {
    for( int i=0;i<size;i++ ) {
        vector<T> perm( &data[0], &data[i+1] );
        do {
            cout << (*this) << endl;
            copy( perm.begin( ),perm.end( ),back_inserter( m_data ) );
            this->sort( m_data.begin( ), m_data.end( ) );
        } while( next_permutation( perm.begin( ), perm.end( ) ) );
        m_data.clear( );
    }     
}

template<typename S> ostream& operator<< ( ostream &stream, Sorters::Sorter<S> &sorter ) {
    copy( sorter->m_data.begin( ),sorter->m_data.end( ), ostream_iterator<S>( stream," " ) );
    return stream;
}
#endif

ОБНОВЛЕНИЕ Я написал небольшой пример, так что я знаю, что моя концепция работает, она просто запутывается, когда я использую полиморфизм и функции друзей.

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

using namespace std;

class Sample {
    public:
        Sample( ) { };
        Sample( float *data, int size ) {
            copy(&data[0],&data[size],back_inserter( m_data ) );
        };
        ~Sample( ) { };
    private:
        vector<float> m_data;
        friend ostream& operator<< ( ostream &stream, Sample &s ) {
            copy( s.m_data.begin( ), s.m_data.end( ), ostream_iterator<float>( stream, " " ) );  
            return stream;
        }
};

int main( int argc, char *argv[] ) {
    float data[ ] = {1,2,3,4,5};
    Sample s(data,5);
    cout << s;
}

РЕШЕНИЕ

Now to write the actual algorithm. I noticed though if I move m_data up to the parrent class I get compiler errors saying that m_data cannot be found. I guess that just means Insertion Sort, Radix Sort, Stooge Sort, ... will all have there own container.

#ifndef SORTERS_H_
#define SORTERS_H_
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cmath>
#include <ctime>
#include <assert.h>

using std::vector;
using std::cin;
using std::cout;
using std::endl;
using std::ostream_iterator;
using std::istream_iterator;
using std::next_permutation;
using std::back_inserter;
using std::ostream;

namespace Sorters {
    template<typename T>
    class Sorter {
        public:
            Sorter( ) { };
            virtual ~Sorter( ) { };
            virtual void test_and_sort( T *data, int size )=0;
        protected:
            virtual void sort( typename vector<T>::iterator left, typename vector<T>::iterator right )=0;
    };

    template<typename T>
    class QuickSorter : public Sorter<T> {
        public:
            QuickSorter( ) { };
            virtual ~QuickSorter( ) { };
            virtual void test_and_sort( T *data, int size );
        private:
            vector<T> m_data;
            virtual void sort( typename std::vector<T>::iterator left, typename std::vector<T>::iterator right );
            friend ostream& operator<< ( ostream &stream, const QuickSorter &sorter ) {
                copy( sorter.m_data.begin( ),sorter.m_data.end( ),ostream_iterator<T>( stream," " ) );
                return stream;
            }
    };
}

template<typename T>
void Sorters::QuickSorter<T>::sort( typename vector<T>::iterator left, typename vector<T>::iterator right ) {

}

template<typename T>
void Sorters::QuickSorter<T>::test_and_sort( T *data, int size ) {
    for( int i=0;i<size;i++ ) {
        vector<T> perm( &data[0], &data[i+1] );
        do {
            copy( perm.begin( ),perm.end( ),back_inserter( m_data ) );
            cout << (*this) << endl;
            this->sort( m_data.begin( ), m_data.end( ) );
            m_data.clear( );
        } while( next_permutation( perm.begin( ), perm.end( ) ) );
    }
}
#endif

Ответы [ 3 ]

3 голосов
/ 03 августа 2011

Первое, что вы печатаете адрес, печатая this.Вам нужно напечатать как

cout << *this << endl;

В комментариях вы упомянули, что вы получаете ошибки.Это из-за следующей строки в operator << ():

vector<S> copy = sorter.m_data;  // <--- where is 'm_data' ??

sorter имеет тип class Sorter<S> и внутри нее нет m_data.

Чтобы это исправить, переместите m_data с QuickSorter на Sorter или перегрузите operator << с помощью QuickSorter<S>&.

2 голосов
/ 03 августа 2011

Вы определяете перегрузку operator << вне пространства имен Sorters.Ошибкадля перегрузки при последующем использовании).

1 голос
/ 03 августа 2011

Почему код, как показано, действует так, как он это объясняет в комментариях: cout << this печатает указатель, что приводит к выводу адреса.Ваша перегрузка operator << ожидает ссылку на объект, а не указатель, поэтому он не используется.Как вы сказали, решение этой проблемы заключается в использовании cout << *this.

Когда я вносил это изменение, я получал ошибку компоновщика.Где-то между шаблонами и пространствами имен что-то запуталось, и мне неясно, что именно.Поэтому я сделал простое решение: определить функцию в классе.

Вместо

template<typename T>
struct QuickSorter {
   template<typename T> friend ostream& operator <<(ostream&, QuickSorter<T>&);
}

template<typename T>
ostream& operator <<(ostream&, QuickSorter<T>&) { }

Я сделал

template<typename T>
struct QuickSorter {  
   friend ostream& operator <<(ostream&, QuickSorter&) { }
};

Теперь вам не нужно беспокоиться о правильной настройке параметров шаблона и еще много чего.В любом случае шаблонные функции должны быть объявлены как встроенные, так что вы можете просто сделать это и покончить с этим.Обратите внимание, что вы также не объявляете operator << как сам шаблон ... вы заинтересованы только в том, чтобы дружить с одной перегрузкой, для конкретного T, который используется классом.

Тогда,вам сообщают, что функция обращается к члену m_data, которого нет в Sorter<T>.Это просто: Sorter<T> не имеет этого члена;QuickSorter<T> делает.Поэтому измените второй параметр функции на QuickSorter<T>&, чтобы компилятор мог найти этот конкретный член.Это изменение также отражено выше.

Последнее, что я хотел бы сделать, это заставить перегрузку оператора принять const QuickSorter<T>& вместо неконстантной.Он никак не изменяет объект, поэтому нет никаких причин не делать этого.

...