1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
|
#include <iostream>
#include <string>
template < typename T > struct list // assumption: T is copy consructible ie. template < std::copy_constructible T >
{
list() = default ; // initialise head and tail to nullptr
~list() { while( !empty() ) pop_front() ; } // release owned resources (nodes) on destruction
bool empty() const noexcept { return head == nullptr ; }
void push_back( const T& v )
{
if( empty() ) head = tail = new node(v) ;
else
{
tail->next = new node(v) ;
tail = tail->next ;
}
}
void pop_front() noexcept
{
if( !empty() )
{
node* t = head ;
head = head->next ;
if( empty() ) tail = nullptr ;
delete t ;
}
}
void print( std::ostream& stm = std::cout ) const
{
std::size_t slno = 0 ; // zero-based serial number
for( const node* n = head ; n != nullptr ; n = n->next )
stm << "(#" << slno++ << "). " << n->data << " => " ;
stm << "nullptr\n" ;
}
private:
struct node // node is an implementation detail
{
T data ;
node* next ;
explicit node( const T& data, node* next = nullptr ) : data(data), next(next) {}
};
node* head = nullptr ;
node* tail = nullptr ;
// non-copyable and non-asignable (for now)
list( const list& ) = delete ;
list& operator= ( const list& ) = delete ;
};
// test list of T by inserting items from the input range one by one,
// and then removing items one by one till the list is empty
// assumption: input range contains a sequence of values which can be implicitly converted to T
// ie. template < typename T, std::ranges::input_range INPUT_RANGE > requires std::constructible_from< T, std::ranges::range_value_t<INPUT_RANGE> >
template < typename T, typename INPUT_RANGE > void test( const INPUT_RANGE& input_range )
{
std::cout << "\n-----------------------------------------\n" ;
list<T> lst ; // there is no good reason to create the list using new
for( const auto& v : input_range )
{
lst.push_back(v) ;
lst.print() ;
}
std::cout << '\n' ;
while( !lst.empty() )
{
lst.pop_front() ;
lst.print() ;
}
std::cout << "\n-----------------------------------------\n" ;
}
int main()
{
const int a[] { 123, 234, 345, 456, 567, 678, 789 } ;
test<int>(a) ;
const char* const b[] { "cero", "uno", "dos", "tres", "cuatro", "cinco" } ;
test<std::string>(b) ; // can convert const char* to std::string
}
|