
Even better, don't use vector<const char*>. What o you need that for?
Here's a real motivating example where I want to use vector<const char*>. I have a large file containing null-terminated strings which I memory map. After opening the file, I construct some sort of index of those strings in a sorted vector. Then I search for things using std::equal_range, std::lower_bound, or similar.
All those algorithms comes in a version that accepts a predicate, so you would still be able to do your optimization.. And it would be clear to anyone who's reading the code what your intention is (to avoid copies), it's simply not a 'coincidence' that there happened to be an overload that matched your types. For clarity and maintenance, I prefer to speak out clearly in code the intention. If it becomes to boilerplate-ly kind of thing, wrap it up in an own algorithm.
The important thing is that for efficiency the algorithms mustn't create temporary strings; they must compare the const char* with the string that I'm searching for directly. std::string provides operator overloads to do this. I want the algorithms to use those heterogeneous comparisons.
I understand the first part about not creating temporaries, but not why you want to use those heterogeneous comparisons. If it's a performance concern, I would prefer being in control of that explicitly. If you're unlucky while working with the code at some point in the future and happen to introduce an implicit copy, everything will compile and run but your speed will be not what you expected. If you're lucky it will crash and can be debugged early on
Dave Abrahams has said a couple of times that he doesn't even know what it means to try to do this. This baffles me, but I trust that there is some validity in his argument. But it does lead me to the point that I made in my review, and my answer to Marshall's question at the start of this thread: I don't want Boost to waste time on either of those none_of_equal implementations. We are all capable of writing our own 4-line none_of_equal implementations that do precisely what we want them to do. Why argue about which is the "one true way" to do it, when we can all have whichever one we prefer? Instead, let's spend time on things where the implementation is more than 4 lines long - like a variant of std::list with O(1) splice!
If we can't get the simple ones right, there's not a healthy ground to base more complicated algorithms on. Also, I don't want to write those 4 lines of code which is potentially dangerous, simply because I wasn't aware of the implications. If I can read in some boost rationale like 'this is how it should be done and why' (many Boost libraries takes this higher moral ground, which I appreciate), then I've learned something.
Regards, Phil.
cheers, Christian