4

I want to erase all the elements that do not satisfy a criterion. For example: delete all the characters in a string that are not digit. My solution using boost::is_digit worked well.

struct my_is_digit {
 bool operator()( char c ) const {
  return c >= '0' && c <= '9';
 }
};

int main() {
 string s( "1a2b3c4d" );
 s.erase( remove_if( s.begin(), s.end(), !boost::is_digit() ), s.end() );
 s.erase( remove_if( s.begin(), s.end(), !my_is_digit() ), s.end() );
 cout << s << endl; 
 return 0;
}

Then I tried my own version, the compiler complained :( error C2675: unary '!' : 'my_is_digit' does not define this operator or a conversion to a type acceptable to the predefined operator

I could use not1() adapter, however I still think the operator ! is more meaningful in my current context. How could I implement such a ! like boost::is_digit() ? Any idea?

Update

Follow Charles Bailey's instruction, I got this code snippet compiled, however the output is nothing:

struct my_is_digit : std::unary_function<bool, char> {
    bool operator()( char c ) const {
        return isdigit( c );
    }
};

std::unary_negate<my_is_digit> operator !( const my_is_digit& rhs ) {
    return std::not1( rhs );
}

int main() {
    string s( "1a2b3c4d" );
    //s.erase( remove_if( s.begin(), s.end(), !boost::is_digit() ), s.end() );
    s.erase( remove_if( s.begin(), s.end(), !my_is_digit() ), s.end() );
    cout << s << endl;  
    return 0;
}

Any idea what was wrong?

Thanks,
Chan

roxrook
  • 13,511
  • 40
  • 107
  • 156
  • `std::unary_function` is wrong. Also if you're referring to me, my name is "Charles Bailey", not "Bailey". – CB Bailey Jan 03 '11 at 09:56
  • @Charles Bailey: I really apologize for mistyping your full name. I already edited. Could I ask you what's wrong with std::unary_function ? ^^! Thanks. – roxrook Jan 03 '11 at 10:01
  • Well, it should be `std::unary_function`. If you won't to type less feel free to call be Charles. Abbreviating my first name doesn't work in my language/culture/personal opinion. – CB Bailey Jan 03 '11 at 10:02
  • @Charles Bailey: just saw your answer. Got it ;) ! Thank you very much for your patience ^_^ ! – roxrook Jan 03 '11 at 10:02
  • @Charles Bailey: Thanks for pointing out. To be cross-culture, I will spell out full-name from now on. Thank you. – roxrook Jan 03 '11 at 10:04

2 Answers2

11

You should be able to use std::not1.

std::unary_negate<my_is_digit> operator!( const my_is_digit& x )
{
    return std::not1( x );
}

For this to work you have to #include <functional> and derive your my_is_digit functor from the utility class std::unary_function< char, bool >. This is purely a typedef helper and adds no runtime overhead to your functor.


Complete working example:

#include <string>
#include <algorithm>
#include <functional>
#include <iostream>
#include <ostream>

struct my_is_digit : std::unary_function<char, bool>
{
    bool operator()(char c) const
    {
        return c >= '0' && c <= '9';
    }
};

std::unary_negate<my_is_digit> operator!( const my_is_digit& x )
{
    return std::not1( x );
}

int main() {
    std::string s( "1a2b3c4d" );
    s.erase( std::remove_if( s.begin(), s.end(), !my_is_digit() ), s.end() );
    std::cout << s << std::endl;
    return 0;
}
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • I'm pretty sure you don't need to provide the type explicitly for `std::not1`. It's a template function and can deduce the type from the object, no? Also, the predicate needs to be derived from `unary_function`. – In silico Jan 03 '11 at 09:29
  • @Charles Bailey: Thanks for your quick reply. Although I could use not1, I still prefer the way boost::is_digit provides ! operator. – roxrook Jan 03 '11 at 09:32
  • @Charles Bailey: I'm pretty sure `std::not1` is a function template. C++ standard 20.3.5 says that `std::not1` has a signature of `template unary_negate not1(const Predicate& pred);`, which is a function declaration. – In silico Jan 03 '11 at 09:34
  • @Chan: Well, you can add an overloaded `!` operator to your functor to return a negated functor but that's just moving the negator somewhere else. – CB Bailey Jan 03 '11 at 09:35
  • @In silico: You're right! I was thinking of a manual invocation of `std::unary_negate` for some reason. Have deleted my misleading comment. – CB Bailey Jan 03 '11 at 09:38
  • @Bailey: I'm not sure I understand your solution. Would you mind giving me a brief example? – roxrook Jan 03 '11 at 09:39
  • @Charles Bailey: That's okay, I was just making sure I understood what I read. :-) – In silico Jan 03 '11 at 09:40
  • 1
    @Chan: Just add a free function: `std::unary_negate< my_is_digit > operator!( const my_is_digit& x ) { return std::not1( x ); }` – CB Bailey Jan 03 '11 at 09:42
  • @Chan: For information, this is the boost `operator!` http://www.boost.org/doc/libs/1_45_0/doc/html/boost/algorithm/operator__id1133588.html – CB Bailey Jan 03 '11 at 09:48
  • @Bailey: Thanks, I got it compiled, however the output was none. Did I miss something? – roxrook Jan 03 '11 at 09:49
2

How could I implement such a ! like boost::is_digit()

...presumably you could look at the code that forms the is_digit implementation? You will see predicate_facade and the relevant code:

template<typename PredT>
inline detail::pred_notF<PredT>
operator!( const predicate_facade<PredT>& Pred )
{
// Doing the static_cast with the pointer instead of the reference
// is a workaround for some compilers which have problems with
// static_cast's of template references, i.e. CW8. /grafik/
return detail::pred_notF<PredT>(*static_cast<const PredT*>(&Pred)); 
}
ta.speot.is
  • 26,914
  • 8
  • 68
  • 96
  • 1
    Thanks for your suggestion, and I actually checked the source of boost::is_digit. However, it was way more complex than I can imagine. So I'm looking for a simpler solution in this case. – roxrook Jan 03 '11 at 09:37