www.digitalmars.com         C & C++   DMDScript  

c++.stlsoft - select_1st + listbox_add_inserter

reply "Pablo Aguilar" <paguilarg hotmail.com> writes:
Why aren't both functionals designed to work together?

I've a function that fills a map<string,string> with name/path pairs. Later 
I want to display the names in a listbox, for which I'd type something like:

std::for_each(
      m_files.begin()
    , m_files.end()
    , select_1st<listbox_add_inserter>()
);

Of course that doesn't specify what list to add to, but something pretty 
much like that would help...
Now, suppose I give up on that and want to use boost's bind, I'd write:

std::for_each(
      m_files.begin()
    , m_files.end()
    , boost::bind(
          listbox_add_inserter(list_hwnd)
        , boost::bind(select_1st< ? >(), _1)
    )
);

I'd need the select_1st functional anyway, because I only want to ad the 
"first", but what would I type it with?

Just a thought...
(sgi's stl and stlport have select1st and select2nd that do support this, 
the second case, I mean) 
Oct 11 2004
parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
select_1st and select_2nd are very neglected, originally misunderstood
(by their hapless author), components that are +vely screaming out for
some attention, if not a wholesale rewrite.

I'd be *very* happy if you were to describe exactly how you'd like them
to work, and I'll make it so for 1.8.3.

FYI, I've just written c_str_ptr_extractor, which can be used to apply
c_str_ptr to items within an algorithm. The actual code in which it's
used is (hold your breath):

    std::vector<std::string> inputFiles;


stlsoft::r_copy(stlsoft::make_sequence_range(winstl::findfile_sequence(f
ileSpec)),
stlsoft::c_str_ptr_extractor(std::back_inserter(inputFiles)));

In other words, it copies the names of all the file-system elements that
match fileSpec into the string vector inputFiles, applying c_str_ptr()
to the value type of each step in the enumeration before applying it to
the back_inserter (which converts into std::string and push_back's on
the inputFiles). I reckon this is bordering on the limit of what's
comprehensible to reasonable human beings who are, like me, good, but
not guru, in C++. What do you think?

Also, I recall that you complained about the listbox/combobox/listview
inserters many months ago. Can you reiterate your complaints, and I'll
address that also in 1.8.3?

Cheers

Matthew

"Pablo Aguilar" <paguilarg hotmail.com> wrote in message
news:ckf4l9$2bu2$1 digitaldaemon.com...
 Why aren't both functionals designed to work together?

 I've a function that fills a map<string,string> with name/path pairs.

 I want to display the names in a listbox, for which I'd type something

 std::for_each(
       m_files.begin()
     , m_files.end()
     , select_1st<listbox_add_inserter>()
 );

 Of course that doesn't specify what list to add to, but something

 much like that would help...
 Now, suppose I give up on that and want to use boost's bind, I'd

 std::for_each(
       m_files.begin()
     , m_files.end()
     , boost::bind(
           listbox_add_inserter(list_hwnd)
         , boost::bind(select_1st< ? >(), _1)
     )
 );

 I'd need the select_1st functional anyway, because I only want to ad

 "first", but what would I type it with?

 Just a thought...
 (sgi's stl and stlport have select1st and select2nd that do support

 the second case, I mean)

Oct 12 2004
parent "Pablo Aguilar" <paguilarg hotmail.com> writes:
 select_1st and select_2nd are very neglected, originally misunderstood
 (by their hapless author), components that are +vely screaming out for
 some attention, if not a wholesale rewrite.

 I'd be *very* happy if you were to describe exactly how you'd like them
 to work, and I'll make it so for 1.8.3.

Well, I guess the way SGI's STL (and STLPort, being based on SGI) does it is good enough... both are templated on the type of pair they receive instead of the operation they apply. Here's an example taken directly from STLPort's help: int main() { map<int, double> M; M[1] = 0.3; M[47] = 0.8; M[33] = 0.1; transform(M.begin(), M.end(), ostream_iterator<int>(cout, " "), select1st<map<int, double>::value_type>()); // The output is 1 33 47. } Here's the example from Stlsoft's help: std::for_each(m.begin(), m.end(), stlsoft::select_1st<dump_key>()); (Remember I once asked about your preference for for_each?) The difference here, is that stlport's select1st is returning the "first" part, while stlsoft's is applying the parameterized operation. Now, the way I see it, stlport's is usable with boost's compose, allowing for complex operations (like the one you describe below), while stlsoft's isn't up to it. The main point here, is that the operation to apply is specified as a template paramter, disallowing then, the use of functor's which require an object to act upon (listbox_add_inserter ring a bell? It requires the list's HWND) and you just can't do that with the template parameter. So consider the following code I posted before: <Original> std::for_each( m_files.begin() , m_files.end() , select_1st<listbox_add_inserter>() ); </Original> <Proposed> std::for_each( m_files.begin() , m_files.end() , boost::bind( listbox_add_inserter(list_hwnd) , boost::bind(select_1st< ? >(), _1) ) ); </Proposed> If the select_1st component worked like STLPort's, then the question mark need only be replaced by files_type::value_type (which would be the type of the pairs it'd expect to receive) In summary, you can't have the operation to execute be a template parameter, because that excludes functors which require what to act upon (listbox_add_inserter, back_inserter, etc.) Actually the one proposal is to have it act like stlport's. Now, in my particular case, you know I can't just use stlport's functional header, since changing the stl is an all or nothing deal. Also, stlport's select1st (and 2nd, of course) is a non standard extension, meaning I HAVE to use stlport to get it, while Stlsoft, being an independent library, well, just doesn't have any standard to conform to! And I know if I need that component I just download what I need (rather than the all or nothing package as with the stl)
 FYI, I've just written c_str_ptr_extractor, which can be used to apply
 c_str_ptr to items within an algorithm. The actual code in which it's
 used is (hold your breath):

    std::vector<std::string> inputFiles;


 stlsoft::r_copy(stlsoft::make_sequence_range(winstl::findfile_sequence(f
 ileSpec)),
 stlsoft::c_str_ptr_extractor(std::back_inserter(inputFiles)));

 In other words, it copies the names of all the file-system elements that
 match fileSpec into the string vector inputFiles, applying c_str_ptr()
 to the value type of each step in the enumeration before applying it to
 the back_inserter (which converts into std::string and push_back's on
 the inputFiles). I reckon this is bordering on the limit of what's
 comprehensible to reasonable human beings who are, like me, good, but
 not guru, in C++. What do you think?

I don't think it's hard to comprehend... it's what boost's bind is all about! I'm almost certain this is equivalent code: stlsoft::r_for_each( stlsoft::make_sequence_range(winstl::findfile_sequence(fileSpec)) , boost::bind( boost::mem_fn(&std::vector<std::string>::push_back) , &inputFiles , boost::bind( winstl_ns_qual(c_str_ptr) , _1 ) ) ); It basically means: take inputFiles and apply the push_back method with "the result of applying c_str_ptr to the input value" as a paramter. There is one drawback though, c_str_ptr having been overloaded many times, is an ambigous name in the code above, and you have to disambiguate it yourself, which isn't pretty! The point is though, that it's not that "out of this world" (I think!) and in fact simplifies what would've otherwise been written uglier! (We do agree your version is simpler right?) I don't consider myself very good either, but I have written code pretty much like this and think it's ok and somewhat understandable (that is, if you are familiar with boost's bind and mem_fn). So I guess your new extractor would be welcome (as long as it saves having to write bothersome one or two line structs!) by us masoquistic programmers who would write stuff like this!
 Also, I recall that you complained about the listbox/combobox/listview
 inserters many months ago. Can you reiterate your complaints, and I'll
 address that also in 1.8.3?

Oh, they weren't complaints, they were requests. I said it'd be nice to have inserters which took pairs and did insertions of both the string and a data object. Something like the following: operator()(pair const& p) { int idx = SendMessage(m_hWnd, LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(c_str_ptr(p.first))); assert(idx != LB_ERR); assert(idx != LB_ERRSPACE); SendMessage(m_hWnd, LB_SETITEMDATA, idx, reinterpret_cast<LPARAM>(p.second)); } where p.second could be something like a pointer, or and index into an external data source, or something like that. Well, have fun reading...
Oct 12 2004