3

So I am currently writing a part of a program that takes user text input. I want to ignore all input characters that are not alphabetic, and so I figured std::isalpha() would be a good way to do this. Unfortunately, as far as I know there are two std::isalpha() functions, and the general one needs to be disambiguated from the locale-specific one thusly:

(int(*)(int))std::isalpha()

If I don't disambiguate, std::isalpha seems to return true when reading uppercase but false when reading lowercase letters (if I directly print the returned value, though, it returns 0 for non-alpha chars, 1 for uppercase chars, and 2 for lowercase chars). So I need to do this.

I've done so in another program before, but for some reason, in this project, I sometimes get "ISO C++ forbids" errors. Note, only sometimes. Here is the problematic area of code (this appears together without anything in between):

std::cout << "Is alpha? " << (int(*)(int))std::isalpha((char)Event.text.unicode) << "\n";

if ( (int(*)(int))std::isalpha((char)Event.text.unicode) == true)
{
    std::cout << "Is alpha!\n";
    //...snip...
}

The first instance, where I send the returned value to std::cout, works fine - I get no errors for this, I get the expected values (0 for non-alpha, 1 for alpha), and if that's the only place I try to disambiguate, the program compiles and runs fine.

The second instance, however, throws up this:

error: ISO C++ forbids comparison between pointer and integer

and only compiles if I remove the (int(*)(int)) snippet, at which point bad behavior ensues. Could someone enlighten me here?

GarrickW
  • 2,181
  • 5
  • 31
  • 38
  • 3
    Why do you perform the comparison `== true`? Don't do that. It's redundant from a readability standpoint and causes problems when comparing with a result that can be non-zero to indicate 'truth'. – Michael Burr Oct 08 '12 at 16:27
  • Can you please provide an [SSCCE](http://www.sscce.org/) of the problem? I've only had to apply the cast to `is*` functions to disambiguate them from their locale aware counterparts when passing the functions around as predicates to algorithms, not in the use case you're describing. – Praetorian Oct 08 '12 at 16:27
  • Hm, bad habit I suppose. I've just removed it and now it compiles AND works fine, so thanks! But I don't really understand why, though. Even if the return type is int, wouldn't you be able to compare it with a bool anyway, and all non-zero values would be true? – GarrickW Oct 08 '12 at 16:29

2 Answers2

3

You are casting the return value of the std::alpha() call to int(*)(int), and then compare that pointer to true. Comparing pointers to boolean values doesn't make much sense and you get an error.

Now, without the cast, you compare the int returned by std::alpha() to true. bool is an integer type, and to compare the two different integer types the values are first converted to the same type. In this case they are both converted to int. true becomes 1, and if std::isalpha() returned 2 the comparison ends up with 2 != 1.

If you want to compare the result of std::alpha() against a bool, you should cast that returned in to bool, or simply leave out the comparison and use something like if (std::isalpha(c)) {...}

sth
  • 222,467
  • 53
  • 283
  • 367
  • But isn't anything within the parentheses of if() compared to true if not otherwise specified? – GarrickW Oct 08 '12 at 16:41
  • Ah, thank you for the explanation re: boolean and integer comparison! Now I understand. – GarrickW Oct 08 '12 at 16:56
  • huh? I thought std::isalpha returns a boolean? - thats what http://www.cplusplus.com/reference/std/locale/isalpha/ says. (and why do you discuss std::alpha in the answer) – Tom Oct 08 '12 at 16:59
  • @Tom You're linking to the locale-specific function, but I was using this one: http://www.cplusplus.com/reference/clibrary/cctype/isalpha/ – GarrickW Oct 08 '12 at 17:13
2

There is no need to disambiguate, because the there is no ambiguity in a normal call.

Also, there is no need to use the std:: prefix when you get the function declaration from <ctype.h>, which after C++11 is the header you should preferably use (i.e., not <cctype>) – and for that matter also before C++11, but C++11 clinched it.

Third, you should not compare the result to true.

However, you need to cast a char argument to unsigned char, lest you get Undefined Behavior for anything but 7-bit ASCII.

E.g. do like this:

bool isAlpha( char const c )
{
    typedef unsigned char UChar;
    return !!isalpha( UChar( c ) );
}
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • Thanks for the tip concerning Undefined Behavior, I'll definitely keep that in mind. – GarrickW Oct 08 '12 at 16:56
  • I don't understand what is wrong with using std::isalpha? Why use the c and not the c++ function? Indeed, I thought std::isalpha guaranteed returning a bool. – Tom Oct 08 '12 at 17:04
  • @Tom: there's nothing *wrong* with using `std::isalpha`. you just run an increased risk of the code not working with some other compiler or in some other context, because the declaration might be coming from a [.h] header like ``, which is permitted to drop the name also in the `std` namespace. you're right to ask about this, but you could also have searched SO. `std::isalpha` has [two overloads](http://en.cppreference.com/w/cpp/string/byte/isalpha). one returns `int`, the other `bool`. this, however, was wrong to ask about. you should just have checked the documentation for this. ;-) – Cheers and hth. - Alf Oct 08 '12 at 17:29
  • @Tom: re "why use the c and not the c++ function", well the two main reasons are simplicity and efficiency. the c++ take on locales is not something a c++ programmer is very proud of. as i see it, it is over-engineered, limited, extremely complicated, brittle, lacking in functionality, and historically *not even supported* by e.g. g++ in Windows. i haven't checked how it is with g++ 4.7.1 in windows. but it wouldn't surprise me if it is that way still. so... – Cheers and hth. - Alf Oct 08 '12 at 17:32