Thread: STL style

  1. #1
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130

    STL style

    In my current pet project I try to use the STL as much as possible. There's no real reason except to learn how it works, doing it the old way would probably save me a lot of headaches and even more time. This is a simple function and I could have written it in about 10 other ways to make it work. The goal is to make it work STL style. However, my STL style obsession has it's limits, I'm not going to write a ten line functor of my own to supply to a three line STL function when I can have the whole thing done in one simple loop myself.

    The function digits_only takes a string and removes everything that is not a digit according to the given locale. It took me a while to recognize the remove_if is not really "removing if". However, it takes a single argument to decide if a container element is to be removed, a so-called predicate, a function that takes a container element and returns a bool.

    I tried various variants of what I thought should have worked but was greeted with a lot of cryptic error messages. Sorry for copying only generic english error messages, but I use a German version and those messages are probably even less helpful.

    Code:
    #include <string>
    #include <iostream>
    #include <cctype>
    #include <algorithm>
    #include <locale>
    #include <functional>
    
    using namespace std;
    
    void digits_only( std::wstring& s, const locale& loc = locale("") )
    {
    	wstring::iterator erasor = remove_if( s.begin(), s.end(), std::isdigit );
    	// works fine... except for not doing what I want, I need the digits to stay and remove only the non-digits 
    	// plus, as of now it's not recognizing the supplied locale
    
    	// trying to add a logical not for removing anything that's not a digit:
    
    	//wstring::iterator erasor = remove_if( s.begin(), s.end(), logical_not( std::isdigit ) ); 
    	// error C2440: 'conversion' : cannot convert from 'type1' to 'type2'
    	
    	//wstring::iterator erasor = remove_if( s.begin(), s.end(), logical_not( std::isdigit<wchar_t> ) ); 
    	// error C2440: 'conversion' : cannot convert from 'type1' to 'type2'
    	
    	//wstring::iterator erasor = remove_if( s.begin(), s.end(), not1( std::isdigit<wchar_t> ) ); 
    	// error C2784: 'declaration' : could not deduce template argument for 'type' from 'type'
    
    	// gave up and tried to bind the locale as a second parameter first
    
    	//wstring::iterator erasor = remove_if( s.begin(), s.end(), bind2nd( std::isdigit, loc ) ); 
    	// error C2896 'function1 ' : cannot use function template 'function2' as argument. 
                   	
    	//wstring::iterator erasor = remove_if( s.begin(), s.end(), bind2nd( std::isdigit<wchar_t>, loc ) ); 
    	// error C2784 'declaration' : could not deduce template argument for 'type' from 'type'
    
    
    	s.erase( erasor, s.end() );
    }
    
    int main()
    {
    	wstring text = L"a1b2c3";
    
    	digits_only( text );
    
    	wcout << text << endl;
    
    	return 0;
    }
    hth
    -nv

    She was so Blonde, she spent 20 minutes looking at the orange juice can because it said "Concentrate."

    When in doubt, read the FAQ.
    Then ask a smart question.

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Code:
    s.erase(
      std::remove_if( s.begin(), s.end(),
        std::bind2nd(std::isdigit, loc)
      ),
      s.end()
    );
    The bind2nd could be better replaced with boost::bind or std::tr1::bind:
    Code:
    namespace p = std::tr1::placeholders;
    // ...
    std::tr1::bind(std::isdigit, p::_1, loc)
    The syntax is, I think, more intuitive.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130
    hm, I never heard of tr1, interesting read, it has a lot of things I could really use, although I think our perception of "intuitive" differs

    Does the first line you posted compile for you ? I get three errors, C2896 once and C2784 twice on that line and I wonder why, it looks correct. I'm using VS2003.
    hth
    -nv

    She was so Blonde, she spent 20 minutes looking at the orange juice can because it said "Concentrate."

    When in doubt, read the FAQ.
    Then ask a smart question.

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    It does not, in fact. I forgot that bind2nd can only bind to functors with the correct nested typedefs, which a function reference/pointer isn't. Also, std::isdigit is a template, so you have to explicitly instantiate it. This leads to this line:
    Code:
    std::bind2nd(std::ptr_fun(std::isdigit<char>), loc)
    And this still doesn't work, because apparently it forms a reference to a reference.

    All in all, std::tr1::bind is so far superior that you really should use it (or boost::bind, if you don't have std::tr1 yet) instead.



    As for what is intuitive, it's syntax you'll quickly get familiar with. You might also want to learn functional languages to appreciate function composition. (And then laugh at C++ for its clumsy syntax. )
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    the hat of redundancy hat nvoigt's Avatar
    Join Date
    Aug 2001
    Location
    Hannover, Germany
    Posts
    3,130
    Well, I can't use boost at work and VS doesn't have tr1, so I'm going to loop myself Thanks anyway.
    hth
    -nv

    She was so Blonde, she spent 20 minutes looking at the orange juice can because it said "Concentrate."

    When in doubt, read the FAQ.
    Then ask a smart question.

  6. #6
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    You could also create your own function for remove_if() to use:
    Code:
    	wstring::iterator erasor = remove_if( s.begin(), s.end(), is_not_digit );
    .
    .
    bool is_not_digit(wchar_t c)
    {
       return !std::isdigit(c);
    }
    I tried playing around with not1(isdigit), but also couldn't get it to compile. I also std::tr1, but my compiler apparently doesn't have it.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. WM_CAPTION causing CreateWindowEx() to fail.
    By Necrofear in forum Windows Programming
    Replies: 8
    Last Post: 04-06-2007, 08:23 AM
  2. Button handler
    By Nephiroth in forum Windows Programming
    Replies: 8
    Last Post: 03-12-2006, 06:23 AM
  3. WS_EX_COMPOSITED style (double buffering) problems
    By JasonD in forum Windows Programming
    Replies: 2
    Last Post: 10-12-2004, 11:21 AM
  4. include question
    By Wanted420 in forum C++ Programming
    Replies: 8
    Last Post: 10-17-2003, 03:49 AM
  5. Tab Controls - API
    By -KEN- in forum Windows Programming
    Replies: 7
    Last Post: 06-02-2002, 09:44 AM