Home > Archive > VC STL > February 2005 > Binary predicate for std::list::unique() in VC++ 6?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Binary predicate for std::list::unique() in VC++ 6?
|
|
| David Carr 2005-02-14, 9:11 pm |
| Hi all,
I am trying to accomplish using a binary predicate in the unique() method
for the list class, using VC++ v6.0sp5. I have had no success. Ultimately,
I am trying to achieve a unique list of paths that is case insensitive. I
have seen a historical posting by trusty Igor Tandetnik that required
changing the source for <list>. In terms of building and deployment, this
is not an option for me.
So first and foremost, is it possible with this dev. env. to use predicates
in list::unique()? More generally in the rest of STL as part of VC++ 6sp5?
If not, which version of VS.NET resolves this?
If so, perhaps someone would be interested to check out whether I have made
some error below.
// MODULE MyTest.cpp
#include <String>
#include <List>
static bool PathsEqual(const std::string sP1, const std::string sP2)
{
// Dummy return value for now
return false;
}
void F(void)
{
std::list<std::string> MyDirs;
// Populate the list...
// Output the list and check
MyDirs.sort();
MyDirs.unique(PathsEqual);
// Output the list and check
}
Thanks in advance for your assistance.
Cheers,
David
| |
| Craig Kelly 2005-02-14, 9:11 pm |
| "David Carr" wrote:
> Hi all,
>
> I am trying to accomplish using a binary predicate in the unique() method
> for the list class, using VC++ v6.0sp5. I have had no success.
> Ultimately,
> I am trying to achieve a unique list of paths that is case insensitive. I
> have seen a historical posting by trusty Igor Tandetnik that required
> changing the source for <list>. In terms of building and deployment, this
> is not an option for me.
>
> So first and foremost, is it possible with this dev. env. to use
> predicates
> in list::unique()? More generally in the rest of STL as part of VC++
> 6sp5?
>
> If not, which version of VS.NET resolves this?
>
> If so, perhaps someone would be interested to check out whether I have
> made
> some error below.
<snip>
David,
According to the docs I have for VC 6, the list<> member "template<class T>
void unique(T pr)" is replaced by "void unique(not_equal_to<T> pr) because
VC 6 doesn't support member template functions. The best solution I can
think of is a functor that derives from not_equal_to, so your code would
become
#include <string>
#include <list>
#include <functional>
using namespace std;
struct paths_eq: public not_equal_to<std::string>
{
bool operator()(const std::string& lhs, const std::string& rhs)
{
// Dummy return value for now
return false;
}
};
void F(void)
{
std::list<std::string> MyDirs;
// Populate the list...
// Output the list and check
MyDirs.sort();
MyDirs.unique(paths_eq());
// Output the list and check
}
This compiled with VC 6. I believe this was fixed with the next release of
the VC compiler (one fo the .NET's, don't know the name of the first one:)
Your code compiled as is for me on VC.NET 2003 (and GCC 3.2 on cygwin if you
care).
Craig
| |
| Tom Widmer 2005-02-14, 9:11 pm |
| Craig Kelly wrote:
> "David Carr" wrote:
>
>
>
>
> <snip>
>
> David,
>
> According to the docs I have for VC 6, the list<> member "template<class T>
> void unique(T pr)" is replaced by "void unique(not_equal_to<T> pr) because
> VC 6 doesn't support member template functions. The best solution I can
> think of is a functor that derives from not_equal_to, so your code would
> become
I'm afraid that's not going to work - not_equal_to<T>::operator() is not
a virtual function!
>
> #include <string>
> #include <list>
> #include <functional>
>
> using namespace std;
>
> struct paths_eq: public not_equal_to<std::string>
> {
> bool operator()(const std::string& lhs, const std::string& rhs)
> {
> // Dummy return value for now
> return false;
> }
> };
>
> void F(void)
> {
> std::list<std::string> MyDirs;
> // Populate the list...
> // Output the list and check
>
> MyDirs.sort();
> MyDirs.unique(paths_eq());
In the above, paths_eq() gets sliced into a not_equal_to object, and
not_equal_to still ends up being called.
> // Output the list and check
> }
>
> This compiled with VC 6. I believe this was fixed with the next release of
> the VC compiler (one fo the .NET's, don't know the name of the first one:)
> Your code compiled as is for me on VC.NET 2003 (and GCC 3.2 on cygwin if you
> care).
Yup, the library was fixed for VC7.0.
There are two working solutions. One is to specialize not_equal_to for
your type. The other is to modify the list header to make unique a
template member, since that does just about work with VC6, just not with
VC5 for which the library was originally written.
Tom
| |
| Craig Kelly 2005-02-14, 9:11 pm |
| "Tom Widmer" wrote:
<snipping my inane previous post>
> I'm afraid that's not going to work - not_equal_to<T>::operator() is not a
> virtual function!
<snip>
> In the above, paths_eq() gets sliced into a not_equal_to object, and
> not_equal_to still ends up being called.
You know, I wouldn't feel so stupid if I had just gotten about C++
inheritance and conversion mechanisms... but somehow in my late-night
posting brain I decided that binary_function defined operator() as virtual
and that VC6's list::unique defined as unique(no_equal_to<T>&). Which is
really stupid considering the fact that I actually posted the correct
signature!
Thank you for correcting me.
> The other is to modify the list header to make unique a template member,
> since that does just about work with VC6
I didn't know this! I vastly prefer VC 7.x but I'll keep that in mind for
the future... Thanks again for stopping my (well-intended) campaign of
ignorance :)
Craig
| |
| David Carr 2005-02-14, 9:11 pm |
| Thanks Tom & Craig. The suggestion to modify the <list> header was also
something I had seen suggested by Igor on Google Groups, but needed to avoid
for this implementation.
I defaulted to a more simple (yes, inelegant) approach - convert all the
paths to uppercase and leave unique() be. I need to read up on how to
'specialize' not_equal_to, as this I do not know.
Glad to hear that it is possible in VC7/2003.
Cheers,
David
"Tom Widmer" <tom_usenet@hotmail.com> wrote in message
news:%23xzUacsAFHA.824@TK2MSFTNGP11.phx.gbl...
> Craig Kelly wrote:
method[color=darkred]
I[color=darkred]
this[color=darkred]
T>[color=darkred]
because[color=darkred]
>
> I'm afraid that's not going to work - not_equal_to<T>::operator() is not
> a virtual function!
>
>
> In the above, paths_eq() gets sliced into a not_equal_to object, and
> not_equal_to still ends up being called.
>
of[color=darkred]
one:)[color=darkred]
you[color=darkred]
>
> Yup, the library was fixed for VC7.0.
>
> There are two working solutions. One is to specialize not_equal_to for
> your type. The other is to modify the list header to make unique a
> template member, since that does just about work with VC6, just not with
> VC5 for which the library was originally written.
>
> Tom
| |
| Jerry Coffin 2005-02-14, 9:11 pm |
| In article <O8vNDeoAFHA.1260@TK2MSFTNGP12.phx.gbl>,
David_Carr@NoSpamCanada.Com says...
> Hi all,
>
> I am trying to accomplish using a binary predicate in the unique() method
> for the list class, using VC++ v6.0sp5. I have had no success. Ultimately,
> I am trying to achieve a unique list of paths that is case insensitive. I
> have seen a historical posting by trusty Igor Tandetnik that required
> changing the source for <list>. In terms of building and deployment, this
> is not an option for me.
Many people treat std::list as more or less the default choice of
collections, to be used unless they're sure they really need
something else.
IMO, it should be roughly the opposite: your last choice, to be used
only when you're reasonably certain nothing else will do. Unless you
have at least one iterator that's always maintained pointing to
somewhere in the middle of the list, you should probably be using
some other collection.
In this case, the first question is whether you ever really need
things in the original order, or whether they can be sorted at all
times. The second question is whether you can store only unique
paths, or you really need the duplicates at some point.
My guess is that it's perfectly fine if they're always sorted and
unique. If that's the case, what you really want is almost certainly
set::set. Using it, what you've asked for so far can look like this:
bool I_strcmp(std::string const &a, std::string const &b) {
return stricmp(a.c_str(), b.c_str());
}
std::set<std::string, I_strcmp> MyDirs;
// populate set
// unique and sort happened automatically while populating
// output list and check:
std::copy(MyDirs.begin(), MyDirs.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
--
Later,
Jerry.
The universe is a figment of its own imagination.
| |
| Tom Widmer 2005-02-14, 9:11 pm |
| David Carr wrote:
> Thanks Tom & Craig. The suggestion to modify the <list> header was also
> something I had seen suggested by Igor on Google Groups, but needed to avoid
> for this implementation.
>
> I defaulted to a more simple (yes, inelegant) approach - convert all the
> paths to uppercase and leave unique() be. I need to read up on how to
> 'specialize' not_equal_to, as this I do not know.
Like so:
#include <functional>
#include <string>
namespace std
{
//strictly speaking it is illegal to specialize std:: classes for
//std::string, although you can do this for user defined types.
template<>
struct not_equal_to<string>
{
bool operator()(const std::string& lhs, const std::string& rhs) const
{
// Dummy return value for now
return false;
}
};
}
....
mylist.unique(std::not_equal_to<std::string>());
However, this has the slightly alarming side effect of altering how
not_equal_to works for string for the whole program. Modifying the
headers may be better - you can place the modified <list> file on your
project include path so that it gets used before the system include (I
haven't tried this).
Tom
|
|
|
|
|