What is no matching function for call to 'isPalindrome'? - c++

top 35/3_palindrome.cpp:18:8: error: no matching function for call to 'isPalindrome'
if(isPalindrome(s)){
^~~~~~~~~~~~
top 35/3_palindrome.cpp:4:5: note: candidate function not viable: no known conversion from 'std::__1::string' (aka 'basic_string<char,
char_traits<char>, allocator<char> >') to 'char *' for 1st argument
int isPalindrome(char* s){
^
1 error generated.
The terminal process "/bin/zsh '-c', ' g++ -g 'top 35/3_palindrome.cpp' -o 3_palindrome.out && clear && ./3_palindrome.out'" terminated with exit code: 1.
My code:
#include <bits/stdc++.h>
using namespace std;
int isPalindrome(char* s){
int n = strlen(s);
for (int i = 0; i < n/2; i++){
if(s[i] != s[n - i - 1]){
return 0;
}
}
return 1;
}
int main(){
string s;
getline(cin,s);
cout << s;
if(isPalindrome(s)){
cout << "Yes";
}
else{
cout << "No";
}
return 0;
}

The Problem
Your isPalindrome function expects char * for its argument. There is no suitable implicit conversion (operator or otherwise) from what you're giving it, a std::string, to that char *. The compiler is dutifully pressing on and attempting to find an alternative overload of isPalindrome that matches what you're actually feeding it. Finding none, the resulting error halts the compile and leaves you with your not-necessarily-crystal-clear error message.
A Solution
There are a multitude of solutions, but the easiest is simply to change isPalindrome to accept a reference to const std::string:
bool isPalindrome(std::string const& s)
{
std::size_t n = s.length();
for (std::size_t i=0; i<n/2; ++i)
{
if(s[i] != s[n - i - 1])
return false;
}
return true;
}
A More-C++ Solution
All you're really doing is comparing two ranges. The standard library provides a function to do this, std::equal , which takes an iterator begin/end, and a secondary iterator starting point (and after C++14, a secondary ending point). Furthermore, the std::string class provides both fore and aft direction iterators (begin() and rbegin(), and the lot of them can be used to do this:
#include <iostream>
#include <string>
#include <algorithm>
bool isPalindrome(std::string const& s)
{
return std::equal(s.begin(), std::next(s.begin(), s.length()/2), s.rbegin());
}
Note that neither this, nor your original C-based approach, will work with mixed-case comparison. I.e. Aba will certainly not compare as a successful palindrome. More work is involved if you want that. Also, the three-argument overload of std::equal is available until, but not including, C++20, after that you need the four argument version (the second range also requires an end-iterator; not just a starting point).
Noteworthy
Neither #include <bits/stdc++.h> or using namespace std are good ideas, and should be avoided. There are woefully inadequate web sites and online "courses" that preach using both almost by reflex; just... don't. If you want know more about why these are terrible practices I urge you to read:
Why should I not #include <bits/stdc++.h>?
Why is “using namespace std;” considered bad practice?

Take a closer look at the error:
if(isPalindrome(s)){
palindrome.cpp:4:5: note: candidate function not viable: no known conversion from 'std::__1::string' (aka 'basic_string<char,
char_traits, allocator >') to 'char *' for 1st argument
So let's break it down:
1- if(isPalindrome(s)){
That's the line that failed compiling. The line has an if statement, a call to the isPalindrome function, and a reference to variable s. It also has some C syntax related to those, ( ( )){. The error could be in any of those. You do have an arrow to the isPalindrome function, so that's our best bet, but not necessarily the root cause yet.
2- palindrome.cpp:4:5:
That's an offending line (or at least, a line related to your issue). What this line does,
int isPalindrome(char* s){
is just declare a function. So now we know the issue is at least related to your function declaration, confirming the suspicion above.
2- candidate function not viable:
this goes a bit more detail into what the problem with that function is.
Each function call has to be matched to a function declaration. C++ accepts (function overloading)[https://en.wikipedia.org/wiki/Function_overloading], so given a function call, the compiler will find all "candidate" functions, that is, those that have a matching name. Between those, the compiler will look at certain hints, such as the types you're passing in, to determine which implementation to use.
The error here declares that there is no viable function. So there was no function that could be matched to the call you're making.
3- *no known conversion from 'std::__1::string' [...] to 'char ' for 1st argument:
Now this is the remaining piece we need. The compiler tells you that in the best candidate function it found, for the first (and only) argument, there is a type mismatch. The function expects a char *, but the argument being used in your call can't be converted to a char *. The argument you're passing is of type std::string, and that can't be converted to a char * automatically.
There are several ways to fix this, but the easiest route is to change your types so that either the variable you pass in is a char *, or the function you're defining expects the type you're passing in, that is, std::string.
As someone mentioned above, one way to achieve this, among several others, is to just add s.c_str() to your function call, instead of purely passing in s. That is a manual conversion from std::string to char *.
In general though, converting types with manual calls isn't a good solution from a performance or maintainability standpoint. You'd be better off just reimplementing either your function or your input reading to use the same type throughout, be it std::string or char *.

Related

Comparing element in string with length-1 string in C++

I am sorry for the simple question, but I cannot understand why this simple program does not work.
What is a[0] supposed to be other than "a"?
#include <iostream>
using namespace std;
int main(){
string a = "abcd";
string b = "a";
if (a[0]==b){//<------problem here
cout << a << endl;
}
return 0;
}
which returns the error
no match for ‘operator==’ (operand types are ‘char’ and ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’)
or simply using string c=a[0]; returns the error:
conversion from ‘char’ to non-scalar type ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’ requested
PS: after trying a few things, I can get it to work if I compare a[0]==b[0] or assign c[0]=a[0] because those are now definitely the same type, but I still would like to know what the standard and/or fastest way to carry out a comparison of a substring with another string in C++ is.
You should use std::string::find to find substrings. Using the subscript operator on string returns a single character (scalar), not a string (vector, non-scalar); therefore, they are not the same type and there is no defined comparison.
You can can also use std::string::substr to select a substring which you can directly compare against another string.
Example
#include <iostream>
#include <string>
int
main() {
std::string a = "abcd";
std::string b = "a";
if (a.find(b) != std::string::npos) {
std::cout << a << "\n";
}
if (a.substr(0, 1) == b) {
std::cout << a << "\n";
}
return 0;
}
References
http://en.cppreference.com/w/cpp/string/basic_string/find
http://en.cppreference.com/w/cpp/string/basic_string/substr
http://en.cppreference.com/w/cpp/string/basic_string
what is a[0] supposed to be other than "a"?
It is an 'a' not "a" and it is a char. You cannot compare a char to a string because they are different types. But what you can do is extract a substring from your string that is the length of 1 character:
if (a.substr(0,1)==b)...
Then you will be comparing "a" to "a" because .substr returns a string not a char, even if the length is 1.
Also don't forget to #include <string> if you are working with std::string.
a[0] is a character, which has the value 'a', whereas b is a string, which has a different type. This will work if an operator ==(char, string) is defined (or some variant with const's and/or ref's) but there isn't, at least in the C++ standard, so the compilation should fail. The clang compiler even gives the helpful message,
invalid operands to binary expression ('int' and 'string'...
which indicates that you're comparing different types.
Try changing it to compare a[0] and b[0]. The bracket operator is defined for strings, and returns a character, so you can compare them that way.
edit: This may look as if it doesn't answer the question. It does answer the original question; the OP changed the entirety of the question after the fact (and someone added a corresponding answer) but the original question is still there in the first paragraph. I'll delete the answer if moderators want.

Can std::string::c_str() be used whenever a string literal is expected?

I would guess that the last two lines in this code should compile.
#include "rapidjson/document.h"
int main(){
using namespace rapidjson ;
using namespace std ;
Document doc ;
Value obj(kObjectType) ;
obj.AddMember("key", "value", doc.GetAllocator()) ; //this compiles fine
obj.AddMember("key", string("value").c_str(), doc.GetAllocator()) ; //this does not compile!
}
My guess would be wrong, though. One line compiles and the other does not.
The AddMember method has several variants as documented here, but beyond that... why is the return of .c_str() not equivalent to a string literal?
My understanding was that where ever a string literal was accepted, you could pass string::c_str() and it should work.
PS: I'm compiling with VC++ 2010.
EDIT:
The lack of #include <string> is not the problem. It's already included by document.h
This is the error:
error C2664: 'rapidjson::GenericValue<Encoding> &rapidjson::GenericValue<Encoding>::AddMember(rapidjson::GenericValue<Encoding> &,rapidjson::GenericValue<Encoding> &,Allocator &)'
: cannot convert parameter 1 from 'const char [4]' to 'rapidjson::GenericValue<Encoding> &'
with
[
Encoding=rapidjson::UTF8<>,
Allocator=rapidjson::MemoryPoolAllocator<>
]
and
[
Encoding=rapidjson::UTF8<>
]
EDIT2:
Please ignore the fact that .c_str() is called on a temporal value. This example is just meant to show the compile error. The actual code uses a string variable.
EDIT3:
Alternate version of the code:
string str("value") ;
obj.AddMember("key", "value", doc.GetAllocator()) ; //compiles
obj.AddMember("key", str, doc.GetAllocator()) ; // does not compile
obj.AddMember("key", str.c_str(), doc.GetAllocator()) ; // does not compile
The std::string::c_str() method returns a char const*. The type of a string literal is char const[N] where N is the number of characters in the string (including the null terminator). Correspondingly, the result of c_str() can not be used in all places where a string literal can be used!
I'd be surprised if the interface you are trying to call requires a char array, though. That is, in your use it should work. It is more likely that you need to include <string>.
even if this code compiled:
obj.AddMember("key2", string("value").c_str(), doc.GetAllocator());
You cannot guarantee that it is safe.
The const char* returned by std::string::c_str() will be valid until the end of this statement.
If the AddMember method stores a copy of the string itself, all well and good. If it stores a pointer then you're doomed. You need knowledge of the inner workings of AddMember before you can reason about the correctness of your code.
I suspect the authors have already thought of this and have constructed overloads that demand that you either send in a std::string object (or equivalent) or a string literal reference (template<std::size_t N> void AddMember(const char (&str)[N]))
Even if this is not what they had in mind, they might be looking to protect you from yourself, in case you inadvertently send in an invalid pointer.
While seemingly an inconvenience, this compile time error indicates a possibly-faulty program. It's a tribute to the library's authors. Because compile time errors are a gazillion times more useful than runtime errors.
Looking at the documentation you linked to, it seems like you are trying to call the overload of AddMember taking two StringRefTypes (and an Allocator). StringRefType is a typedef for GenericStringRef<Ch>, which has two overloaded constructors taking a single argument:
template<SizeType N>
GenericStringRef(const CharType(&str)[N]) RAPIDJSON_NOEXCEPT;
explicit GenericStringRef(const CharType *str);
When you pass a string literal, the type is const char[N], where N is the length of the string + 1 (for the null terminator). This can be implicitly converted to a GenericStringRef<Ch> using the first constructor overload. However, std::string::c_str() returns a const char*, which cannot be converted implicitly to a GenericStringRef<Ch>, because the second constructor overload is declared explicit.
The error message you get from the compiler is caused by it choosing another overload of AddMember which is a closer match.
Re
” why is the return of .c_str() not equivalent to a string literal
A string literal is a zero-terminated string in an array with size known at compile time.
c_str() produces a pointer to (the first item in) a zero-terminated string in an array with size known only at run-time.
Usually a string literal expression will be used in a context where the expression decays to pointer to first item, but in some special cases it does not decays. These cases include
binding to a reference to array,
using the sizeof operator, and
forming a larger literal by compile time concatenation of string literals (simply writing them in order).
I think that's an exhaustive list.
The error message you cite,
” cannot convert parameter 1 from 'const char [4]' to 'rapidjson::GenericValue &
… does not match your presented code
#include "rapidjson/document.h"
int main(){
using namespace rapidjson ;
using namespace std ;
Document doc ;
Value obj(kObjectType) ;
obj.AddMember("key1", "value", doc.GetAllocator()) ; //this compiles fine
obj.AddMember("key2", string("value").c_str(), doc.GetAllocator()) ; //this does not compile!
}
Nowhere in this code is there a three character long string literal.
Hence the claims that “this compiles” and “this does not compile”, are not very trustworthy.
You
should have quoted the actual error message and actual code (at least one of them is not what you had when you compiled), and
should have quoted the documentation of the function you're calling.
Also, note that the actual argument that compiler reacts to in the quoted diagnostic, is a literal or an array declared as such, not a c_str() call.

Invalid conversion from char to const char when using Insert function from <string>

OK, I'm trying to work on a monolith of a program, and I've got a decent amount of the errors sorted through. The one's that's mystifying me right now is when I got "invalid conversion from 'char' to 'const char'" for this line:
sequenceMutation.insert( initialPosition, 'T' );
initialPosition itself is meant to be equal to sequenceIleChains[0] + 3, which corresponds to the index of the last character for the first Isoleucine group (plus one to account for the behavior of insert). I don't know why it would be outputting this, considering I initialize and declare string sequenceMutation locally in the function without const, so if anyone can figure this out, it would be useful.
Additionally, if it may help, I used
string sequenceMutation = sequenceOld[sequence];
to initialize and declare sequenceMutation, where sequenceOld is a vector that I pass by reference using vector<string>& sequenceOld and sequence is a integer value I initialize, declare, pass from the for loop in int main() that I'm putting this function within.
Replace the ' by ", you are inserting a string, not a char, see http://www.cplusplus.com/reference/string/string/insert/

Can't find toupper and erase

So, I've been doing Reddit's daily programmer #140 and can't use std::toupper and std::erase.
Includes:
#include <iostream>
#include <string>
#include <cctype>
Part with toupper and erase (used to transform words to 'CamelCase'):
std::string tekst;
std::cin >> tekst;
tekst[0] = std::touppper(tekst[0]);
for(unsigned int i = 0; i < tekst.size(); i++){
if(tekst[i] == 32){
std::erase(tekst[i], 1);
tekst[i] = std::toupper(tekst[i]);
}
}
And compiler shows errors:
error: 'touppper' is not a member of 'std'
error: 'erase' is not a member of 'std'
What can cause it? Thanks in advance!
Not
std::touppper
but
std::toupper
You need to pass a locale to the function, see for example: http://www.cplusplus.com/reference/locale/toupper/
std::touppper does not exist, as it is spelled with two p's, not with three :). std::erase is not a standard function, check this: Help me understand std::erase
You probaly want to use std::toupper() as the basis of your implementation. Note, however, that std::toupper() takes its argument as int and requires that the argument is a positive value of EOF. Passing negative values to the one argument version of std::toupper() will result in undefined behavior. On platforms where char is signed you will easily get negative values, e.g., when using ISO-Latin-1 encoding with my second name. The canonical approach is to use std::toupper() with the char convert to an unsigned char:
tekstr[0] = std::toupper(static_cast<unsigned char>(tekstr[0]));
With respect to erase() you are probably looking for std::string::erase():
tekstr.erase(i);
Note that if the string ends in a space, you don't want to access the character at index i after blowing the last space away!

How to compare boost::string_ref to std::string

I'm trying to make boost::string_ref working as I want to, but I'm facing a problem right now - following code does not compile:
#include <boost/utility/string_ref.hpp>
#include <iostream>
#include <string>
using namespace std;
int main() {
string test = "test";
boost::string_ref rtest(test);
cout << (rtest == "test")<<endl;
}
and the gcc throws 30kB error log, starting with
source.cpp: In function 'int main()':
source.cpp:10:19: error: no match for 'operator==' (operand types are 'boost::string_ref {aka boost::basic_string_ref<char, std::char_traits<char> >}' and 'const char [5]')
cout << (rtest == "test")<<endl;
^
How to compare boost::string_ref to std::string?
Honestly, I'd just avoid using string_ref entirely until it matures. The fact that you can't compare a string_ref to a std::string or a const char * out of the box should set alarm bells ringing (looks like they forgot to write a bunch of comparison operators), and worse, it doesn't look like the library received sufficient testing (e.g. bug 8067!).
Just make a string_ref out of the string. They are very cheap to construct. Though against a string literal, you may want to include the length. Otherwise it's going to iterate once to find the end of the string, and then iterate again to compare them. Just make sure that if you change the string, you keep the count up to date.
cout << (rtest == boost::string_ref("test",4)) << endl;
With a std::string, you don't need to worry about the count, because string_ref will just call the size() member function, which is also very cheap.