0
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;
}
Alan Birtles
  • 22,711
  • 4
  • 22
  • 44
Dhinesh
  • 35
  • 5
  • 2
    It means your `getPalindrome` function expects a `char *` whilst you're providing a `std::string`. After searching for a suitable overload, none was found; thus your error. Unrelated, both `#include ` and `using namespace std;` are dreadful habits and should be broken sooner rather than later. Read [here](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h) and [here](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) for why. If some instructor is insisting you use them, insist on a different instructor. – WhozCraig Nov 03 '20 at 06:07
  • `string` is not a `char *`. To obtain a `char *` from a `std::string` that can be passed to your function, use the `c_str()` member i.e. `if (isPalindrome(s.c_str())`. For that to work, you will ALSO need to change the signature of `isPalindrome()` to `int isPalindrome(const char *s)` (indicating that the function will not change the data pointed to by the argument `s`). – Peter Nov 03 '20 at 06:08
  • @Peter I think your comment could be turned into an answer to get this out of the list of unanswered questions. – Yunnosch Nov 03 '20 at 06:16
  • 1
    Interesting. `isPalindrome` just looks like it was copy/pasted from some other solution to the same/similar problem, but written in C. – WhozCraig Nov 03 '20 at 06:19
  • 1
    Why don't you just make `isPalindrome()` accept `std::string`? – Barmar Nov 03 '20 at 06:19
  • @Barmar - It could - and, in fact, would be the better solution. I didn't suggest it, since I wasn't interested in rewriting any code within the body of the function (`strlen()` does not accept a `std::string`, so at least one change there). – Peter Nov 03 '20 at 06:50

2 Answers2

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:

WhozCraig
  • 59,130
  • 9
  • 69
  • 128
  • I think most agree that `using` statements are fine in implementation files, and in certain types of applications, such as programming competitions, they are quite standard--those are often the websites preaching using them by reflex. It's hard to issue a blanket advice. – roim Nov 03 '20 at 06:58
  • @roim Actually, it was easy to issue such blanket advise; I just did. And frankly, i'd rather someone take the conservative road and only wander off it once they know what they're doing than the other way around. It is far easier to bend the rules when you've been firmly abiding by the for years rather than never know they existed in the first place and spend time hunting down why `char alpha[10];` pukes in your compilation. And note, I didn't say no "using statements ", I targeted that one *specifically*. – WhozCraig Nov 03 '20 at 07:05
  • Ok, fair, it’s hard to issue *correct* blanket advice. – roim Nov 03 '20 at 10:47
0

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 *.

roim
  • 4,161
  • 2
  • 22
  • 29