0
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
  string str;
  cin>>str;
  str.erase(remove_if(str.begin(), str.end(), isspace),str.end());
  cout<<str;
  return 0;
}

ERROR MSG:

/home/satish/Desktop/CPP/Remove_Spaces/main.cpp|9|error: no matching function for call to ‘remove_if(std::basic_string::iterator, std::basic_string::iterator, )’|

0x90
  • 39,472
  • 36
  • 165
  • 245
Satish Patel
  • 1,784
  • 1
  • 27
  • 39

5 Answers5

4

First off, std::isspace is declared in <cctype> so include that.

Secondly, you need to disambiguate the overload by casting the function to an explicit type:

str.erase(
    remove_if(str.begin(), str.end(), static_cast<int(*)(int)>(isspace)),
    str.end());

Third, as James remarked, this causes undefined behaviour for all characters which aren’t in the ASCII range, and since you cannot generally exclude this, you need to make an effort to ensure that only positive character codes are passed to std::isspace:

bool char_isspace(char c) {
    return std::isspace(static_cast<unsigned char>(c));
}

…

str.erase(
    remove_if(str.begin(), str.end(), char_isspace),
    str.end());
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 2
    Except that calling this version of `isspace` with a `char` is undefined behavior on most systems. – James Kanze Sep 03 '13 at 11:08
  • Because the standard (C) says so. "The header declares several functions useful for classifying and mapping characters In all cases the argument is an int, _the value of which shall be representable as an unsigned char_ or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined." (Emphisis added.) A plain `char`, when converted to an `int`, will result in negative values, which aren't representable as an `unsigned char`. – James Kanze Sep 03 '13 at 12:10
  • @James So are you saying that in C, calling `isspace('ß')` is undefined since a plain character literal has type `int` and can be signed? – Konrad Rudolph Sep 03 '13 at 12:15
  • Yes. Mostly, you'll just get random results, of course, because the traditional implementation of `isspace` just uses the parameter as an index into a table (and the memory preceding the table will usually be mapped). At least one implementation I've used (Sun C) actually duplicated part of the table before its label, so the negative indexes worked---except for `isspace( 'ÿ' )`, because the code for `'ÿ'` happens to be -1, the same as `EOF`. – James Kanze Sep 03 '13 at 12:19
  • @James. Thanks for the information, I didn’t know that. I hate C with a passion. – Konrad Rudolph Sep 03 '13 at 12:22
  • @KonradRudolf On rereading your comment: `'ß'` has type `char` in C++, so it could result in a negative value when converted to `int`. In C, the character literal has type `int`, and presumably won't have a negative value. But you don't usually call `isspace` et al. on a character literal; you know its value. You can call it on the return value of `std::istream::get()` (or `getc`, which is really what it was designed for); if you call it on a value in a `char`, however, you do have to convert to `unsigned char` first. – James Kanze Sep 03 '13 at 12:24
  • @KonradRudolf This is _not_ one of C's best points. Of course, if you live in the US, and believe that characters which aren't present on a US keyboard can't possibly exist in a string, regardless of where the string comes from, you can ignore the problem. (I first learned C in Germany, and have been dealing with the problem for some 30 years now.) – James Kanze Sep 03 '13 at 12:27
3

As was denoted in the comments, you are missing the include for std::isspace, namely <cctype>. But even then you won't have success, because isspace is overloaded see here.

The solution to the overload problem would be to explicitly cast the function pointer to the desired function sgnature:

str.erase(remove_if(str.begin(), str.end(), static_cast<int(*)(int)>(&std::isspace)),str.end());

However, as has been noted in the comments, the isspace used here has undefined behavior if it gets non-ASCII characters. In that case it would be preferable to use the templated version taking a locale as second parameter:

C++14:

str.erase(
  remove_if(str.begin(), str.end(), 
    [](auto c){ return isspace(c, cin.getloc());}
  ),
str.end());

C++11: as above, with the lambda taking a char c as parameter (no polymorphic lambdas in C++11).

C++03 with boost: using boost::bind to create the predicate for remove_if

str.erase(
  remove_if(str.begin(), str.end(), 
    boost::bind(&std::isspace<char>, _1, boost::ref(cin.getloc()))
  ),
str.end());

C++03 without boost: defining a handwritten functor as predicate

struct IsSpace {
  bool operator()(char c) {
    return std::isspace(c, cin.getloc());
  }
};

str.erase(
  remove_if(str.begin(), str.end(), 
    IsSpace()
  ),
str.end());
Community
  • 1
  • 1
Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
  • @KonradRudolph yes. The accepted answer however mentions that the overloads exist. Changed the link to refer to that answer. – Arne Mertz Sep 03 '13 at 10:22
  • Sorry, I still had the link to the `std::isspace` documentation open and thought erroneously that you had linked to that page. – Konrad Rudolph Sep 03 '13 at 10:26
  • Same comment as for @KonradRudolph: you _cannot_ call the version of `std::isspace` which takes a single argument with a `char`. It's undefined behavior. – James Kanze Sep 03 '13 at 11:09
  • @JamesKanze only if you pass non-ascii characters. However, I updated the answer to take that into account – Arne Mertz Sep 03 '13 at 12:11
  • @ArneMertz He's got a `std::string` from somewhere. How can you be sure that there are no negative values in it. (Are there any systems left today which use plain ASCII.) – James Kanze Sep 03 '13 at 12:12
  • The convenience functions `std::isspace`, etc. are generally not very efficient (since they will extract the facet each time they are called). It's usually better to extract the `ctype` facet you need once, and use it. – James Kanze Sep 03 '13 at 12:14
  • And your C++14 version is very bad style. I can't think of any case where you'd want to obfuscate the type involved (except maybe in a template). – James Kanze Sep 03 '13 at 12:15
  • @JamesKanze he had to cope with the UB issue anyways, and it was not the primary issue the question is about. Therefore I left it out in the first version of my answer. Efficiency does not seem to be an issue until now, but of course one can write something more efficient (and probably less readable). – Arne Mertz Sep 03 '13 at 12:45
  • I can't see where the C++14 example is bad style, and have not seen anyone else denoting it as bad style. After all, that's one of the reasons for auto: hiding the explicit type where it is unimportant. It's obvious that the parameter is some kind of character value, and its unimportant what kind exactly. You wouldn't ban things like `auto it = begin(x)`, because it "obfuscates" the type of the iterator. And yes, it's also taking into account that code such as this could go into a template. – Arne Mertz Sep 03 '13 at 12:47
  • @ArneMertz I doubt that efficiency is really an issue, and for a one of use, why not? But typically, something along this line will be needed over and over, in which case, it's better to do it right, and write a functional object. – James Kanze Sep 03 '13 at 13:17
  • @ArneMertz As for `auto`, it's certain that to date, we've not seen too much abuse of it. Given that most people don't have access to compilers which support it. But C++ is a strictly typed language, and that strict typing is there for a purpose. It helps to catch errors. Using `auto` every where is a good way of loosing that advantage. – James Kanze Sep 03 '13 at 13:19
1

Since all of the answers so far involve undefined behavour...

The "simplest" solution, for a one of use, if you have C++11, is:

str.erase(
    std::remove_if(
        str.begin(),
        str.end(), 
        []( char ch ) { return isspace( static_cast<unsigned char>( ch ) ); } ),
    str.end() );

Without the cast to unsigned char, the input to isspace will fail the (unchecked) preconditions of the function is plain char is signed.

If you don't have C++11, or you're going to need this sort of thing (skipping whitespace, etc.) in other places as well, you can write a separate predicate functional object:

struct IsSpace
{
    bool operator()( char ch ) const
    {
        return isspace( static_cast<unsigned char>( ch ) );
    }
};

You might also want IsNotSpace and corresponding objects for the rest of the is... functions in <ctype.h>.

Alternatively, you can use the locale aware versions of the functions in <locale>:

template <std::ctype_base>::mask mask, bool is>
class Is
{
    std::locale m_toEnsureLifetime;
    std::ctype<char> const* m_ctype;
public:
    Is( std::locale const& l = std::locale() )
        : m_toEnsureLifetime( l )
        , m_ctype( &std::use_facet<std::ctype<char>>( m_toEnsureLifetime ) )
    {
    }
    bool operator()( char ch ) const
    {
        return m_ctype->is( mask, ch ) == is;
    }
};
typedef Is<std::ctype_base::space, true> IsSpace;
typedef Is<std::ctype_base::space, false> IsNotSpace;
//  ...

Although a bit more complex, it is fully locale aware, and actually requires less code (because the mask can be a template argument).

James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

try this way:

#include <iostream>
#include <string>
#include <algorithm>

struct SpaceRemover
{
    bool operator( )( char _ch ) { return std::isspace( _ch ); }
};

int main( )
{
    std::string strSource = "   type    ddd     ";
    std::cout << "[main] Source string :\""<< strSource << "\"" << std::endl;

    std::string::iterator itEnd = std::remove_if( strSource.begin(), 
                                                  strSource.end(), 
                                                  SpaceRemover( ) );
    strSource.resize( std::distance( strSource.begin(), itEnd ) );

    std::cout << "[main] Result string :\""<< strSource << "\"" << std::endl;

    return 0;
}
axelBrain
  • 46
  • 2
0
#include <iostream>

int main() {
    std::string original =  "   type    ddd     ";
    std::string result;
    for(char c: original) {
        if( ! std::isspace(c)) result += c;
    }
    original.swap(result);
    std::cout << "Modified: " << original << std::endl;
    return 0;
}

If the result size can be predicted (or just taking the original size is good enough), a result.reserve() will improve performance.