Invalid operands to binary expression when using unordered_map? - c++

I'm trying to find if my character hash table contains the first character of a string:
string minWindow(string s, string t) {
unordered_map<char, int> charFinder;
for (int i = 0; i < t.length(); ++i) {
charFinder[t[i]] = 0;
}
cout << charFinder.find(s[0]) == charFinder.end() << endl;
return "hi";
}
But I get this error for some reason. This doesn't make any sense to me. Anyone have any ideas?
Line 8: Char 14: error: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'std::unordered_map<char, int, std::hash<char>, std::equal_to<char>, std::allocator<std::pair<const char, int> > >::iterator' (aka '_Node_iterator<std::pair<const char, int>, __constant_iterators::value, __hash_cached::value>'))
cout << charFinder.find(s[1]) == charFinder.end() << endl;
~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/cstddef:124:5:
note: candidate function template not viable: no known conversion from 'std::ostream' (aka 'basic_ostream<char>') to 'std::byte' for 1st argument
operator<<(byte __b, _IntegerType __shift) noexcept
^
I cutoff the rest of the long error message.

Per Operator Precedence, operator<< has a higher precedence than operator==, so your cout expression:
cout << charFinder.find(s[0]) == charFinder.end() << endl;
Is being evaluated as if you had written it like this:
(cout << charFinder.find(s[0])) == (charFinder.end() << endl);
The compiler error is complaining about passing the std::unordered_map itself to operator<<, which is not what you intended. Look at the error message more carefully, that is exactly what it is pointing out. There is no operator<< for std::ostream that takes a std::unordered_map as input.
To fix this, you need to use parenthesis explicitly to tell the compiler what you really want, eg:
cout << (charFinder.find(s[0]) == charFinder.end()) << endl;
Otherwise, use a bool variable instead:
bool notFound = charFinder.find(s[0]) == charFinder.end();
cout << notFound << endl;
In C++20, you can use std::unordered_map::contains() instead:
cout << charFinder.contains(s[0]) << endl;
That being said, since you are not actually using the character counts at all, you should use std::set instead of std::unordered_map, eg:
string minWindow(string s, string t) {
set<char> charFinder;
for (int i = 0; i < t.length(); ++i) {
charFinder.insert(t[i]);
}
//
// alternatively:
// set<char> charFinder(t.begin(), t.end());
cout << (charFinder.find(s[0]) == charFinder.end()) << endl;
//
// alternatively:
// bool notFound = charFinder.find(s[0]) == charFinder.end();
// cout << notFound << endl;
//
// alternatively:
// cout << charFinder.contains(s[0]) << endl;
return "hi";
}

Problem is with this statement :
cout << charFinder.find(s[0]) == charFinder.end() << endl;
stream insertion operator, << has higher precedence than equality operator, ==.
The statement is same as :
((cout << charFinder.find(s[0])) == charFinder.end()) << endl;
The overloaded operator << of std::cout returns a reference to std::cout.
When compiler encounters that you are comparing a std::ostream object (std::cout) with an iterator which is returned by std::unordered_map.end() it issues an error as std::ostream does not have an overloaded operator == to compare itself with an iterator.

Related

Typeid() Check of Passing Paramaters of A Templated Function

I don't want to use function overload for a small change in a function. Instead, I want to use typeid() check of passing parameter of the templated function below. But, If I don't comment out the line in the code below, it gives the compile error of:
Severity Code Description Project File Line Suppression State
Error invalid operands to binary expression ('basic_ostream<char, std::char_traits<char> >' and 'std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >')
As I understand the compiler does not know how to behave. Is there a solution for this?
The code is :
#include <iostream>
#include <vector>
using namespace std;
template <class T>
void Test(T A)
{
if (typeid(T) == typeid(vector<string>)) {
cout << "The type of A is vector<string>" << endl << endl;
//cout << "First element of A is:" << A[0] << endl; // If I don't comment out this line, it gives the compiler error.
}
if (typeid(T) == typeid(vector<vector<string>>)) {
cout << "The type of A is vector<vector<string>>" << endl;
cout << "First row first element of A is:" << A[0][0] << endl;
}
}
int main()
{
Test(vector<string> {"1", "2", "3"});
Test(vector<vector<string>> { {"11", "12", "13"}, { "21", "22", "23" }});
return 0;
}
The problem is in ordinary if, the statement-true (and statement-false if present) has to be valid statement at compile-time, no matter what's the result of the condition, for every instantiation of Test with the type T given.
You can use constexpr if since C++17 (with std::is_same).
In a constexpr if statement, the value of condition must be a
contextually converted constant expression of type bool. If the value
is true, then statement-false is discarded (if present), otherwise,
statement-true is discarded.
e.g.
if constexpr (std::is_same_v<T, vector<string>>) {
cout << "The type of A is vector<string>" << endl << endl;
cout << "First element of A is:" << A[0] << endl;
}
if constexpr (std::is_same_v<T, vector<vector<string>>>) {
cout << "The type of A is vector<vector<string>>" << endl;
cout << "First row first element of A is:" << A[0][0] << endl;
}
LIVE
Before C++17 you can go with SFINAE or specialization (with templates), or just overloading (even without templates).

Ternary operator compilation

Why does this giving compilation problem at bold line?
#include<iostream>
static int i = 10;
int main() {
**(i) ? (std::cout << "First i = " << i << std::endl) : ( i = 10);**
std::cout << "Second i = " << i << std::endl;
}
Compilation message:
test.c:8: error: invalid conversion from ‘void*’ to ‘int’
Your usage of the ternary operator is a bit weird: based on the value of i, you either print something to std::cout or assign a new value to it. Those actions don't share a connection through the return value of an expression, so don't do it like this. When using the ternary operator, it's best to stay closer to its intended purpose: a short notation for two possible expressions with a dispatch based on a simple predicate. Example:
const int n = i == 0 ? 42 : 43;
Your code should look like this:
if (i == 0)
i = 10;
else
std::cout << "First i = " << i << "\n";
The reason the original snippet did not compile is that there is no common return type of the ternary operator. "Common" means that both expressions can be converted to the return type. E.g., in const int n = i == 0 ? 42 : 43; the return type is int.
The problem comes from the fact that the return values of the expressions in your conditional operator (ternary operator) (std::ofstream in the case of the std::cout ..., and int for i = 10) are incompatible and therefore the conditional operator is ill-formed. Please check the rules for return type of the conditional operator.
In this case, just use a normal conditional:
if (i)
std::cout << "First i = " << i << std::endl;
else
i = 10;

Overload << operator to change " " to "\n"

I am trying to overload
<<
operator. For instance
cout << a << " " << b << " "; // I am not allowed to change this line
is given I have to print it in format
<literal_valueof_a><"\n>
<literal_valueof_b><"\n">
<"\n">
I tried to overload << operator giving string as argument but it is not working. So I guess literal
" "
is not a string. If it is not then what is it. And how to overload it?
Kindly help;
Full code
//Begin Program
// Begin -> Non - Editable
#include <iostream>
#include <string>
using namespace std;
// End -> Non -Editable
//---------------------------------------------------------------------
// Begin -> Editable (I have written )
ostream& operator << (ostream& os, const string& str) {
string s = " ";
if(str == " ") {
os << '\n';
}
else {
for(int i = 0; i < str.length(); ++i)
os << str[i];
}
return os;
}
// End -> Editable
//--------------------------------------------------------------------------
// Begin -> No-Editable
int main() {
int a, b;
double s, t;
string mr, ms;
cin >> a >> b >> s >> t ;
cin >> mr >> ms ;
cout << a << " " << b << " " ;
cout << s << " " << t << " " ;
cout << mr << " " << ms ;
return 0;
}
// End -> Non-Editable
//End Program
Inputs and outputs
Input
30 20 5.6 2.3 hello world
Output
30
20
5.6
2.3
hello
world
" " is a string-literal of length one, and thus has type const char[2]. std::string is not related.
Theoretically, you could thus overload it as:
auto& operator<<(std::ostream& os, const char (&s)[2]) {
return os << (*s == ' ' && !s[1] ? +"\n" : +s);
}
While that trumps all the other overloads, now things get really hairy. The problem is that some_ostream << " " is likely not uncommon, even in templates, and now no longer resolves to calling the standard function. Those templates now have a different definition in the affected translation-units than in non-affected ones, thus violating the one-definition-rule.
What you should do, is not try to apply a global solution to a very local problem:
Preferably, modify your code currently streaming the space-character.
Alternatively, write your own stream-buffer which translates it as you wish, into newline.
Sure this is possible, as I have tested. It should be portable since you are specifying an override of a templated function operator<<() included from <iostream>. The " " string in your code is not a std::string, but rather a C-style string (i.e. a const char *). The following definition works correctly:
ostream& operator << (ostream& os, const char *str) {
if(strcmp(str, " ") == 0) {
os << '\n';
} else {
// Call the standard library implementation
operator<< < std::char_traits<char> > (os, str);
}
return os;
}
Note that the space after std::char_traits<char> is necessary only if you are pre-c++11.
Edit 1
I agree with Deduplicator that this is a potentially dangerous solution as it may cause undesirable consequences elsewhere in the code base. If it is needed only in the current file, you could make it a static function (by putting it within an unnamed namespace). Perhaps if you shared more about the specifics of your problem, we could come up with a cleaner solution for you.
You might want to go with a user defined literal, e.g.
struct NewLine {};
std::ostream& operator << (std::ostream& os, NewLine)
{
return os << "\n";
}
NewLine operator ""_nl(const char*, std::size_t) // "nl" for newline
{
return {};
}
This can be used as follows.
int main(int, char **)
{
std::cout << 42 << ""_nl << "43" << ""_nl;
return 0;
}
Note three things here:
You can pass any string literal followed by the literal identifier, ""_nl does the same thing as " "_nl or "hello, world"_nl. You can change this by adjusting the function returning the NewLine object.
This solution is more of an awkward and confusing hack. The only real use case I can imagine is pertaining the option to easily change the behavior at a later point in time.
When doing something non-standard, it's best to make that obvious and explicit - here, the user defined literal indeed shines, because << ""_nl is more likely to catch readers' attention than << " ".

Cout String and int in ternary operator

A line in my c++ code reads:
cout<<(i%3==0 ? "Hello\n" : i) ;//where `i` is an integer.
But I get this error:
operands to ?: have different types 'const char*' and 'int
How can I modify the code (with minimum characters)?
Ugly:
i%3==0 ? cout<< "Hello\n" : cout<<i;
Nice:
if ( i%3 == 0 )
cout << "Hello\n";
else
cout << i;
Your version doesn't work because the result types of the expressions on each side of : need to be compatible.
You can't use the conditional operator if the two alternatives have incompatible types. The clearest thing is to use if:
if (i%3 == 0)
cout << "Hello\n";
else
cout << i;
although in this case you could convert the number to a string:
cout << (i%3 == 0 ? "Hello\n" : std::to_string(i));
In general, you should try to maximise clarity rather than minimise characters; you'll thank yourself when you have to read the code in the future.
operator<< is overloaded, and the two execution paths don't use the same overload. Therefore, you can't have << outside the conditional.
What you want is
if (i%3 == 0) cout << "Hello\n"; else cout << i;
This can be made a bit shorter by reversing the condition:
if (i%3) cout << i; else cout << "Hello\n";
And a few more characters saved by using the ternary:
(i%3)?(cout<<i):(cout<<"Hello\n");
std::cout << i % 3 == 0 ? "Hello" : std::to_string(i);
But, as all the other answers have said, you probably shouldn't do this, because it quickly turns into spaghetti code.

displaying an iterator to a vector

I am working on a project where I am placing an enum into a vector. and I was wondering how I could get functionality like such out of the vector.
for(int ii = 0; ii < thing.getSize(); ii++){
cout << "thing(" << ii << ") = " << toString(thing[ii]) << endl;
}
I've tried about 5 different ways to do this, and none of them seem to work. I have read through MSDN vector (vector::end() seemed the most helpful until it said that the operator<< wouldn't accept ii as an iterator.
can somebody help me out? the closest I think I got was
vector<int>::iterator ii;
for(ii = things.begin(); ii != things.end(); ii++){ //764
cout << "thing(" << (int)ii << "): " << toString(things[ii]) << endl; //765
}
but this throws errors that either don't make sense or I can't figure out how to solve.
1>c:\...\Project.cpp(764): error C2678: binary '!=' : no operator found which takes a left-hand operand of type 'std::_Vector_iterator<_Myvec>' (or there is no acceptable conversion)
1>c:\...\Project.cpp(765): error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'std::_Vector_iterator<_Myvec>' (or there is no acceptable conversion)
1>c:\...\Project.cpp(765): error C2679: binary '[' : no operator found which takes a right-hand operand of type 'std::_Vector_iterator<_Myvec>' (or there is no acceptable conversion)
The correct generic way to do this is
for(std::vector<int>::const_iterator ii=things.begin();
ii != things.end(); ++ii)
{
std::cout << "thing("
<< std::distance(things.begin(), ii)
<< "): " << *ii << std::endl;
}
is by dereferencing the iterator and using std::distance to get the distance from the beginning.
further more it is generally considered bad to import an entire namespace it is better to either have explicit using statements or a preferably prefix types with it's namespace.
It is also generally preferrable to use the prefix increment operator for iterators.
Also unless you are doing some interesting formatting there is no need to apply 'toString' to an int. As it has a stream operator defined for it.
Try:
cout << "thing(" << (ii - things.begin()) << "): " << toString(*ii) << endl;
Iterators behave pretty much like pointers: they indicate the position of the value and you need to dereference them to get the value:
std::cout << *ii;
things has to be declared as:
vector < int > things;
You can enter your values into the vector like so:
things.push_back( 1 );
things.push_back( 2 );
Then you iterate like this:
for ( vector < int >::iterator i = things.begin(); i != things.end(); ++i )
{
cout << "things( " << ( i - things.begin() ) << " ): " << toString( *i ) << endl;
}