Search code examples
c++c++11stlpalindromeauto

Why can't I use this palindrome function when using an STL list?


I made a palindrome function that allows me to use any container type, and it worked for string, vector, and deque but when I made an STL list and tried running the code, but I get the error bellow and I couldn't figure out what that means and what to do.

Severity    Code    Description Project File    Line    Suppression State
Error   C2676   binary '-': 'std::_List_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>>' does not define this operator or a conversion to a type acceptable to the predefined operator homework4   C:\...\Source.cpp   9   

Severity    Code    Description Project File    Line    Suppression State
Error   C3536   'itr1': cannot be used before it is initialized homework4   C:\...\Source.cpp   9   

Severity    Code    Description Project File    Line    Suppression State
Error   C2676   binary '<': 'std::_List_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>>' does not define this operator or a conversion to a type acceptable to the predefined operator homework4   C:\...\Source.cpp   9   
Severity    Code    Description Project File    Line    Suppression State
Error   C2100   illegal indirection homework4   C:\...\Source.cpp   10  

Visual studio error list

Below the code I ran.

#include <iostream>
#include<list>
#include<vector>
#include<deque>
using namespace std;

template <typename Container>
bool palindrome(const Container& s) {
    for (auto itr = s.begin(), itr1 = s.end() - 1; itr < itr1; itr++, itr1--) {
        if (*itr != *itr1)
            return false;
    }
    return true;
}

void main() {
    const string word1{ "racecar" };
    const vector<char> word2{ 'a', 'b', 'b', 'a' };
    const deque<int> word3{ 83, 84, 65, 84, 83 };
    const list<int> word4{ 83, 84, 65, 84, 83 };
    word4.end();

    cout << palindrome< string >(word1) << endl;
    cout << palindrome< vector<char> >(word2) << endl;
    cout << palindrome< deque<int> >(word3) << endl;
    cout << palindrome< list<int> >(word4) << endl;
}


Solution

  • The standard container std::list has bidirectional iterators. The operator - used in this expression

    itr1 = s.end() - 1
    

    is defined for random access iterators. You could use instead the standard function std::prev declared in the header <iterator> like

    itr1 = std::prev( s.end() )
    

    However in any case the function is invalid because in general the user of the function can pass an empty container. In this case the expression std::prev( s.end() ) has undefined behavior.

    And the operator < is not defined for bidirectional iterators. So this expression

    itr < itr1
    

    also may not be used in the function.

    Moreover the function will not work with arrays because arrays do not have member functions like for example begin().

    The function can look the following way as it is shown in the demonstrative program below.

    #include <iostream>
    #include <iomanip>
    #include <string>
    #include <deque>
    #include <vector>
    #include <list>
    #include <iterator>
    
    template <typename Container>
    bool palindrome( const Container &c ) 
    {
        auto first = std::begin( c );
        auto last  = std::end( c );
    
        while ( first != last && first != --last && *first == *last ) ++first;      
    
        return first == last;
    }
    
    int main() 
    {
        const std::string word1{ "racecar" };
        const std::vector<char> word2{ 'a', 'b', 'b', 'a' };
        const std::deque<int> word3{ 83, 84, 65, 84, 83 };
        const std::list<int> word4{ 83, 84, 65, 84, 83 };
        const char word5[] =  { 83, 84, 65, 84, 83 };
    
        std::cout << std::boolalpha << palindrome( word1 ) << '\n';
        std::cout << std::boolalpha << palindrome( word2 ) << '\n';
        std::cout << std::boolalpha << palindrome( word3 ) << '\n';
        std::cout << std::boolalpha << palindrome( word4 ) << '\n';
        std::cout << std::boolalpha << palindrome( word5 ) << '\n';
    
        return 0;
    }
    

    The program output is

    true
    true
    true
    true
    true
    

    If you want you can specialize the function for random access iterators.