1

I am trying to add a list to a string.

int main() {
std::cout << "Hello, welcome to Jay's Coffee!!\n";

std::string name; std::cout <<"What is your name "; std::cin >> name;
  
std::cout <<"Hello " << name << ", thank you so much for coming in today";

std::list <std::string> menu = {"Black Coffee" "Espresso" "Latte" "Cappucino"};
std::cout << name <<",what would you like from our menu today? Here is what we are serving.\n" << menu;

}

Returns

invalid operands to binary expression ('basic_ostream<char>' and 'std::list<std::string>' (aka 'list<basic_string<char>>'))
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335

5 Answers5

2

There is no operator<< for lists. You have to write a loop. For example

for (auto& item : menu)
{
     std::cout << item << '\n';
}

If you think about it it's obvious why you have to do this yourself. How are you doing to separate the list items? I've chosen to put each item on a new line. You might choose to separate them with commas or spaces or some fancy format. Because there is no obvious single way to print a list there is no predefined way in the C++ library.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
john
  • 85,011
  • 4
  • 57
  • 81
  • You don't _have_ to write a loop, you could use `copy(begin, end, ostream_iterator(cout, '\n'))` or whatever – Useless Jul 28 '22 at 16:08
2

You should write code this way. In c++, you can't print a list directly.

    #include <string>
    #include <list>
    using namespace std;
    
    int main() {
    cout << "Hello, welcome to Jay's Coffee!!\n";
    
    string name; 
    cout <<"What is your name "; 
    cin >> name;
      
    cout <<"Hello " << name << ", thank you so much for coming in today";
    
    list <string> menu = {"Black Coffee", "Espresso", "Latte", "Cappucino"};
    cout << name <<",what would you like from our menu today? Here is what we are serving.\n"  ;
    
    for ( string& s : menu )
    {
        cout << s << '\n';
    }
    
 }
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
alamin39
  • 151
  • 1
  • 8
1

The error message means that the operator << that you are trying to use with your object menu of the type std::list<std::string> is not defined for the class std::list<std::string>.

Also you need to separate strings in the initializer list with commas.

std::list <std::string> menu = {"Black Coffee", "Espresso", "Latte", "Cappucino"};

Otherwise the list will contain only one string due to the concatenation of string literals.

You could define such an operator as shown in the demonstration program below.

#include <iostream>
#include <string>
#include <list>

std::ostream & operator <<( std::ostream &os, const std::list<std::string>& lst )
{
    for ( const auto &s : lst )
    {
        os << s << '\n';
    }

    return os;
}

int main()
{
    std::list <std::string> menu = 
    {
        "Black Coffee", "Espresso", "Latte", "Cappucino"
    };

    std::cout << menu;
}

The program output is

Black Coffee
Espresso
Latte
Cappucino

Or just use the range-based for loop directly in main like

std::cout << name <<",what would you like from our menu today? Here is what we are serving.\n";

for ( const auto &s : menu )
{
    std::cout << s << '\n';
}

Or place the range-based for loop in a separate function similar to the operator << shown above.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

All other answers are correct but here is the better way to do the same

#include <iostream>
#include <algorithm>
#include <list>
 
template <typename T>
std::ostream & operator << (std::ostream & os, const std::list<T> & vec){
  std::for_each (vec.begin () , vec.end() , [&](const auto& val){
   std::cout << val << " ";
  });
  return os;
}

int main () {
  std::list <std::string> menu = {"Black Coffee", "Espresso", "Latte", "Cappucino"};
  std::cout << menu << "\n";
  return 0;
}
zain ul din
  • 1
  • 1
  • 2
  • 23
0

First thing, you didn't define a list: in the declaration of menu, initializer-list elems were not separated by comma (,).

To make it reusable, I'd do it something like this:

#include <iostream>
#include <list>

static const std::string list_sep = ", ";

template<typename C> struct FormattedContainer
{
    FormattedContainer(const C& cont, const std::string& sep = list_sep)
    : cont_(cont)
    , sep_(sep) {}
    
    friend std::ostream& operator<<(std::ostream& os, const FormattedContainer& fc)
    {
        bool first = true;
        for (auto&& e : fc.cont_)
        {
            if (first)
            {
                os << e;
                first = false;
            }
            else
            {
                os << fc.sep_ << e;
            }
        }
        return os;
    }
    
    const C& cont_;
    const std::string sep_;
};

template<typename C>
auto make_fc(const C& cont, const std::string& sep = list_sep)
-> FormattedContainer<C>
{
    return FormattedContainer<C>(cont, sep);
}

int main() {
    std::list <std::string> menu = {"Black Coffee", "Espresso", "Latte", "Cappucino"};
    std::cout << "What would you like from our menu today? Here is what we are serving.\n" << make_fc(menu);
}

This way, you don't need to define operator<< for something in std namespace (which might result in ambiguous calls as others might also define it, don't need to import another namespace, just simply call a wrapper around the type. You can use it with basically any container or iterable type using this method.

lorro
  • 10,687
  • 23
  • 36