no operator found which takes a left-hand operand

I'm getting an error and i'm not sure what it means, I'm trying to compare a value to a vector to get the right input, so if the player enters 2 it will get the second element in the vector and choose that item. It's in the Buy Function in Shop.

Error:

Severity Code Description Project File Line Suppression State
Error C2678 binary '==': no operator found which takes a left-hand operand of type 'Item' (or there is no acceptable conversion)


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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "pch.h"
#include <iostream>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>



class Item
{
	public:
		Item(std::string itemName, int itemBaseCost)
			: mItemName(itemName), mItemBaseCost(itemBaseCost) {}

		int ItemCost() const { return mItemBaseCost; }
		std::string ItemName() const { return mItemName;  }

		friend std::ostream &operator<<(std::ostream& os, Item &item)
		{
			os << "Item Name: " << item.mItemName << '\n';
			os << "Item Cost: " << item.mItemBaseCost << " Credits." << '\n';

			return os;
		}

	private:
		std::string mItemName;
		int mItemBaseCost;
};




class Player
{
	public:
		Player(std::string playerName, int playerCredits)
			:	mPlayerName(playerName), mPlayerCredits(playerCredits){}

		std::string GetPlayerName() const { return mPlayerName; }

		int GetPlayerCredits() const { return mPlayerCredits; }


		void AddItemToPlayerInventory(const Item& item)
		{
			mPlayerInventory.push_back(item);
			mPlayerCredits -= item.ItemCost();
		}

		std::vector<Item> ShowPlayerInventory()
		{
			for (unsigned int i = 0; i < mPlayerInventory.size(); i++)
				std::cout << mPlayerInventory[i] << '\n';

			return mPlayerInventory;
		}

	private:
		std::string mPlayerName;

		std::pair<std::string, int> mPlayerAttackNameAndPower;
		std::vector<Item> mPlayerInventory;

		int mPlayerCredits; //Money
};




class Shop
{
	public:
		void AddItems(std::string itemName, int itemBaseCost)
		{
			mShopInventory.push_back(Item(itemName, itemBaseCost));
		}

		void ShowItems()
		{
			for (unsigned int i = 0; i < mShopInventory.size(); i++)
				std::cout << mShopInventory[i] << "\n";
		}

		void Buy(Player& player)
		{
			std::cout << "Welcome to the shop, what would you like to buy?\n";

			for (unsigned int i = 0; i < mShopInventory.size(); i++)
				std::cout << i + 1 << ") " << mShopInventory[i] << '\n';

			std::cout << ">";

			int choice{};

			std::cin >> choice;

			for(unsigned int i = 0; i < mShopInventory.size(); i++)
			{
				if (std::find(mShopInventory.begin(), mShopInventory.end(), choice) != mShopInventory.end())
				{
					std::cout << "Found!\n";
				}
				else
				{
					std::cout << "Not Found!\n";
				}
			}
		}

	private:
		std::vector<Item> mShopInventory;
};


int main()
{
	Shop shop;

	shop.AddItems("Golden Necklace of Speak Good", 450);
	shop.AddItems("Helmet of Protect Head", 500);
	shop.AddItems("Staff of Magic Stuff", 8000);

	Player player("Chay", 600);

	shop.Buy(player);

	return 0;
}
Last edited on
Looks like the problem is on line 101:
if (std::find(mShopInventory.begin(), mShopInventory.end(), choice) != mShopInventory.end())
mShopInventory contains Item but you search for an int and you can't compare an Item with an int.
What do you want to do?
Your find() call is trying to find an int (choice) in a vector of items.

An int is not an item. You can't compare them for equality.

Actually, find() isn't correct here anyway.
I want to find the vector element that corresponds with the number inputted, So if the player wants to buy the second item, they input 2, and then it gets the second element in the item vector and adds that to the players inventory, but I cant get the comparison to work, I understand they are of different types, but I figured getting the element number would require me to use an integer.
Last edited on
If I understand correctly you just want to check if choice-1 is a valid index? All you need to do then is to compare it to the size of the vector.

1
2
3
4
5
6
7
8
9
std::size_t index = choice - 1; 
if (index < mShopInventory.size())
{
	std::cout << "Found!\n";
}
else
{
	std::cout << "Not Found!\n";
}
I dont think so, I'm basically making a menu, if player selects an item from the shop list, it then finds the item by finding the mShopInventory's corresponding array index, so If I input 2 to buy the second item, it will then check to see if that index is valid, and if it is, then assign that item in the shops vector to the players inventory vector. It has to find the shops inventory vector index and assign it to the players vector inventory.
Last edited on
You mean something like this?

1
2
3
4
5
std::size_t index = choice - 1; 
if (index < mShopInventory.size())
{
	player.AddItemToPlayerInventory(mShopInventory[index]);
}
I believe so, So what it's doing issetting index to choice and setting choice to -1? then if index is less than the size of the vector it sets mShopInventory equal to that vector index correct?
So what it's doing issetting index to choice and setting choice to -1?

It's setting index to choice - 1.

The reason you have to subtract one from choice to get the index is because the number that you printed next to each item was index + 1.

1
2
3
4
for (unsigned int i = 0; i < mShopInventory.size(); i++)
	std::cout << i + 1 << ") " << mShopInventory[i] << '\n';
	               ^                             ^
	             choice                        index


then if index is less than the size of the vector it sets mShopInventory equal to that vector index correct?

If the index is less than the size it means that it is in bounds and the user has made a valid choice.

mShopInventory[index] gives you the item at index index.

Then this item is passed as argument to the player's AddItemToPlayerInventory function which adds the item to the player's mPlayerInventory vector.
Last edited on
So im a little confused on whats going on with this, i've been trying to figure it out for a little while now and I cant seem to:

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
void Buy(Player& player)
		{
			bool isTransactionComplete = false;

			int choice{};

			while (!isTransactionComplete)
			{
				std::cout << "Welcome to the shop, what would you like to buy?\n\n";

				std::cout << "Your current credit balance is: " << player.GetPlayerCredits() << " Credits\n\n";

				ShowShopInventory();

				std::cout << ">";

				std::cin >> choice;

				std::size_t index = choice - 1;

				if (index < mShopInventory.size() && player.GetPlayerCredits() >= mShopInventory[index].ItemCost())
				{
					player.AddItemToPlayerInventory(mShopInventory[index]);
					std::cout << "Your new balance is: " << player.GetPlayerCredits() << " Credits\n";
					std::cout << "Your inventory now has: " << player.ShowPlayerInventory()[index].ItemName() << '\n';
					isTransactionComplete = true;
				}
				else if (player.GetPlayerCredits() < mShopInventory[index].ItemCost())
				{
					std::cout << "You do not have the necessary funds to purchase that item.\n";
					std::cout << "You need " << mShopInventory[index].ItemCost() << " credits, and you have " << player.GetPlayerCredits() << ".\n";
					std::cout << "You need " << mShopInventory[index].ItemCost() - player.GetPlayerCredits() << " more credits to purchase this item.\n\n";
				}
			}
		}


I added a few new items to the shop and when i try to buy them it gives me a runtime error saying the vector subscript is out of range, It says the problem is with this:

std::cout << "Your inventory now has: " << player.ShowPlayerInventory()[index].ItemName() << '\n';

but I thought that it checks to see if its in bounds? so why the errors?

Here is the whole code:

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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include "pch.h"
#include <iostream>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>



class Item
{
	public:
		Item(std::string itemName, int itemBaseCost)
			: mItemName(itemName), mItemBaseCost(itemBaseCost) {}

		int ItemCost() const { return mItemBaseCost; }

		std::string ItemName() const { return mItemName;  }

		friend std::ostream &operator<<(std::ostream& os, Item &item)
		{
			os << item.mItemName << '\n';
			os << "Cost: " << item.mItemBaseCost << " Credits\n";

			return os;
		}

	private:
		std::string mItemName;
		int mItemBaseCost;
};




class Player
{
	public:
		Player(std::string playerName, int playerCredits)
			:	mPlayerName(playerName), mPlayerCredits(playerCredits){}

		std::string GetPlayerName() const { return mPlayerName; }

		int GetPlayerCredits() const { return mPlayerCredits; }


		void AddItemToPlayerInventory(const Item& item)
		{
			mPlayerInventory.push_back(item);
			mPlayerCredits -= item.ItemCost();
		}

		std::vector<Item> ShowPlayerInventory() const
		{
			return mPlayerInventory;
		}

	private:
		std::string mPlayerName;

		std::pair<std::string, int> mPlayerAttackNameAndPower;
		std::vector<Item> mPlayerInventory;

		int mPlayerCredits; //Money
};




class Shop
{
	public:
		void AddItems(std::string itemName, int itemBaseCost)
		{
			mShopInventory.push_back(Item(itemName, itemBaseCost));
		}

		void ShowShopInventory()
		{
			int number = 1;

			for (unsigned int i = 0; i < mShopInventory.size(); i++)
				std::cout << number++ << ") " <<  mShopInventory[i] << "\n";
		}

		void Buy(Player& player)
		{
			bool isTransactionComplete = false;

			int choice{};

			while (!isTransactionComplete)
			{
				std::cout << "Welcome to the shop, what would you like to buy?\n\n";

				std::cout << "Your current credit balance is: " << player.GetPlayerCredits() << " Credits\n\n";

				ShowShopInventory();

				std::cout << ">";

				std::cin >> choice;

				std::size_t index = choice - 1;

				if (index < mShopInventory.size() && player.GetPlayerCredits() >= mShopInventory[index].ItemCost())
				{
					player.AddItemToPlayerInventory(mShopInventory[index]);
					std::cout << "Your new balance is: " << player.GetPlayerCredits() << " Credits\n";
					std::cout << "Your inventory now has: " << player.ShowPlayerInventory()[index].ItemName() << '\n';
					isTransactionComplete = true;
				}
				else if (player.GetPlayerCredits() < mShopInventory[index].ItemCost())
				{
					std::cout << "You do not have the necessary funds to purchase that item.\n";
					std::cout << "You need " << mShopInventory[index].ItemCost() << " credits, and you have " << player.GetPlayerCredits() << ".\n";
					std::cout << "You need " << mShopInventory[index].ItemCost() - player.GetPlayerCredits() << " more credits to purchase this item.\n\n";
				}
			}
		}

	private:
		std::vector<Item> mShopInventory;
};


int main()
{
	Shop shop;

	shop.AddItems("Golden Necklace of Speak Good", 450);
	shop.AddItems("Helmet of Protect Head", 800);
	shop.AddItems("Staff of Magic Stuff", 8000);
	shop.AddItems("Mask of Suffocation", 420);
	shop.AddItems("Dagger of Major Stabness", 230);

	Player player("Chay", 600);

	shop.Buy(player);

	return 0;
}
Last edited on
The index is valid for mShopInventory only. The player's latest bought item is the last element in mPlayerInventory (because it was inserted using push_back).
Last edited on
Ok, I've fixed it with a for loop, probably could have used a range based loop but i'll go back and do all that when I refactor the code. Here is my new code, it seems to work but let me know if there are any logic errors that I'm not catching:

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
class Shop
{
	public:
		void AddItems(std::string itemName, int itemBaseCost)
		{
			mShopInventory.push_back(Item(itemName, itemBaseCost));
		}

		void ShowShopInventory()
		{
			int number = 1;

			for (unsigned int i = 0; i < mShopInventory.size(); i++)
			{
				std::cout << number++ << ") " << mShopInventory[i].ItemName() << "\n";
				std::cout << "Cost: " << mShopInventory[i].ItemCost() << " Credits\n" << "\n";
			}
		}

		void Buy(Player& player)
		{
			bool isTransactionComplete = false;

			int choice{};

			while (!isTransactionComplete)
			{
				std::cout << "Welcome to the shop, what would you like to buy?\n\n";

				std::cout << "Your current credit balance is: " << player.GetPlayerCredits() << " Credits\n\n";

				ShowShopInventory();

				std::cout << ">";

				std::cin >> choice;

				std::size_t index = choice - 1;

				if (index < mShopInventory.size() && player.GetPlayerCredits() >= mShopInventory[index].ItemCost())
				{
					player.AddItemToPlayerInventory(mShopInventory[index]);
					std::cout << "Your new balance is: " << player.GetPlayerCredits() << " Credits\n";

					for(int i = 0; i < player.ShowPlayerInventory().size(); i++)
						std::cout << "Your inventory now has: " << player.ShowPlayerInventory()[i].ItemName() << '\n';

					//isTransactionComplete = true;
				}
				else if (player.GetPlayerCredits() < mShopInventory[index].ItemCost())
				{
					std::cout << "You do not have the necessary funds to purchase that item.\n";
					std::cout << "You need " << mShopInventory[index].ItemCost() << " credits, and you have " << player.GetPlayerCredits() << ".\n";
					std::cout << "You need " << mShopInventory[index].ItemCost() - player.GetPlayerCredits() << " more credits to purchase this item.\n\n";
				}
			}
		}

	private:
		std::vector<Item> mShopInventory;
};



Full code:

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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "pch.h"
#include <iostream>
#include <string>
#include <vector>
#include <iostream>


class Item
{
	public:
		Item(std::string itemName, int itemBaseCost)
			: mItemName(itemName), mItemBaseCost(itemBaseCost) {}

		int ItemCost() const { return mItemBaseCost; }

		std::string ItemName() const { return mItemName;  }

		friend std::ostream &operator<<(std::ostream& os, Item &item)
		{
			return os;
		}

	private:
		std::string mItemName;
		int mItemBaseCost;
};




class Player
{
	public:
		Player(std::string playerName, int playerCredits)
			:	mPlayerName(playerName), mPlayerCredits(playerCredits){}

		std::string GetPlayerName() const { return mPlayerName; }

		int GetPlayerCredits() const { return mPlayerCredits; }


		void AddItemToPlayerInventory(const Item& item)
		{
			mPlayerInventory.push_back(item);
			mPlayerCredits -= item.ItemCost();
		}

		std::vector<Item> ShowPlayerInventory() const { return mPlayerInventory; }

	private:
		std::string mPlayerName;

		std::pair<std::string, int> mPlayerAttackNameAndPower;
		std::vector<Item> mPlayerInventory;

		int mPlayerCredits; //Money
};




class Shop
{
	public:
		void AddItems(std::string itemName, int itemBaseCost)
		{
			mShopInventory.push_back(Item(itemName, itemBaseCost));
		}

		void ShowShopInventory()
		{
			int number = 1;

			for (unsigned int i = 0; i < mShopInventory.size(); i++)
			{
				std::cout << number++ << ") " << mShopInventory[i].ItemName() << "\n";
				std::cout << "Cost: " << mShopInventory[i].ItemCost() << " Credits\n" << "\n";
			}
		}

		void Buy(Player& player)
		{
			bool isTransactionComplete = false;

			int choice{};

			while (!isTransactionComplete)
			{
				std::cout << "Welcome to the shop, what would you like to buy?\n\n";

				std::cout << "Your current credit balance is: " << player.GetPlayerCredits() << " Credits\n\n";

				ShowShopInventory();

				std::cout << ">";

				std::cin >> choice;

				std::size_t index = choice - 1;

				if (index < mShopInventory.size() && player.GetPlayerCredits() >= mShopInventory[index].ItemCost())
				{
					player.AddItemToPlayerInventory(mShopInventory[index]);
					std::cout << "Your new balance is: " << player.GetPlayerCredits() << " Credits\n";

					for(int i = 0; i < player.ShowPlayerInventory().size(); i++)
						std::cout << "Your inventory now has: " << player.ShowPlayerInventory()[i].ItemName() << '\n';

					//isTransactionComplete = true;
				}
				else if (player.GetPlayerCredits() < mShopInventory[index].ItemCost())
				{
					std::cout << "You do not have the necessary funds to purchase that item.\n";
					std::cout << "You need " << mShopInventory[index].ItemCost() << " credits, and you have " << player.GetPlayerCredits() << ".\n";
					std::cout << "You need " << mShopInventory[index].ItemCost() - player.GetPlayerCredits() << " more credits to purchase this item.\n\n";
				}
			}
		}

	private:
		std::vector<Item> mShopInventory;
};


int main()
{
	Shop shop;

	shop.AddItems("Golden Necklace of Speak Good", 450);
	shop.AddItems("Helmet of Protect Head", 800);
	shop.AddItems("Staff of Magic Stuff", 8000);
	shop.AddItems("Mask of Suffocation", 420);
	shop.AddItems("Dagger of Major Stabness", 230);

	Player player("Chay", 60000);

	shop.Buy(player);

	return 0;
}



Also I have this code in my item class:

1
2
3
4
friend std::ostream &operator<<(std::ostream& os, Item &item)
{
	return os;
}


I'm not too familiar with the operator keyword, but I did some research on it for this specific project, I've never used it before outside of here but I thought this let me use Item objects in the output stream, but I delete it and run my code and it still runs just fine, am I missing something?
That operator allows writing:
1
2
Item foo;
std::cout << foo;

But you probably never do that. You have:
1
2
std::cout << foo.ItemName(); // prints a std::string
std::cout << foo.ItemCost(); // prints an int 



Furthermore, your operator prints nothing. It could do:
1
2
3
4
5
std::ostream &operator<<(std::ostream& os, const Item &item)
{
  os << item.ItemName() << " costs " << item.ItemCost();
  return os;
}

This operator does not need to be a friend of Item, because it uses only the public interface of Item.
So if i were to do something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <string>
#include <vector>

std::ostream& operator<<(std::ostream& oss, std::vector<std::string>& str)
{
    for(auto& i : str)
    {
        std::cout << i << '\n';
    }
    return oss;
}


int main()
{
    std::vector<std::string> v_str;
    v_str.push_back("Text");
    v_str.push_back("Text 2");

    std::cout << v_str;

    return 0;
}


What the operator keyword is doing is allowing me to define output behavior for a vector or class object and just simply output it anywhere else? Why doesnt C++ just natively do this without having to write all the operator code?
1
2
3
4
5
6
7
8
9
10
class Foo {
  // code
};

int main() {
  Foo foo( 42 );
  Foo bar( "Hello" );
  Foo gaz = foo + bar; // How to add Foos?
  std::cout << gaz; // I know nice format for Foo. Do you?
}


Lets assume that compiler auto-generates output function for every type. What if 99% of user types want to use non-default format?


Operators are syntactic sugar to make code look simpler. Which do you prefer:
1
2
a = b + c + d;
a = addition( addition( b, c ), d );
What the operator keyword is doing is allowing me to define output behavior for a vector or class object and just simply output it anywhere else?

What the operator keyboard is doing is allowing you to overload an operator, for a specific type.

In this specific case, the operator you are overloading is the << operator, and the type you are overloading it for is your Item class.

Why doesnt C++ just natively do this without having to write all the operator code?

How do you imagine that C++ can magically know how you want your class to be outputted? (Or how you would want it to behave with any other operator, in the general case?)
Furthermore,
The << is a binary operator; it has two operands. The +, -, /, *, % are binary too, but - and * are used also as unary operators; one operand.

The << is conventionally used for two different purposes:
* binary left-shift: foo = lhs << 3;, where the lhs is unsigned integer
* stream output: lhs << rhs;, where lhs is std::ostream

A custom << could perform any operation and the lhs have any type, if that combo is intuitive for the user.
Topic archived. No new replies allowed.