Avoiding Helper Functions for Doing Comparisons - c++

Say I have a type with a member function:
class Thing {
std::string m_name;
public:
std::string & getName() {
return m_name;
}
};
And say I have a collection of that type:
std::vector<Thing> things;
And I want to keep the things in order by name. To do that, I use std::lower_bound to figure out where to put it:
bool thingLessThan(Thing const& thing, std::string const& name) {
return thing.getName() < name;
}
void addThing(std::string const& name) {
vector<Thing>::iterator position = lower_bound(
things.begin(), things.end(),
name,
thingLessThan);
if (position == things.end() || position->getName() != name) {
position = things.insert(position, Thing());
position->getName() = name;
}
}
Is there a way to do the same thing as the thingLessThan function without actually creating a function, perhaps using std::mem_fun, std::less, etc?

Other than a lambda you can simply define an operator< which adheres to strict weak ordering to allow a container of your object to be comparable by STL algorithms with the default predicate std::less
class whatever
{
public:
bool operator<(const whatever& rhs) const { return x < rhs.x; }
private:
int x;
};
std::vector<whatever> v;
std::sort(v.begin(), v.end());

Sure. You can use a lambda expression (assuming your compiler supports it):
vector<Thing>::iterator position = lower_bound(
things.begin(), things.end(),
name,
[](Thing const& thing, std::string const& name) { return thing.getName() < name; });
Of course, an alternative option is just to define operator< for the class, then it will be used by default, if you don't specify another comparer function for std::lower_bound.

Depending on what your purpose is? If you just like the syntactic niceness of not declaring something to be used in one place, use lambda expressions to create an anonymous function.

You can overload operator<() and use std::less<T> if you don't want to write predicates contantly. Also you can use lambda-expressions, which would be much nicer, because operator<() is logically connected only with things, that can be put in some order in obvious ways, like numbers or strings.

If you use a std::map, the strings will be placed in alphabetical order automatically. If you want to modify the ordering further, create your own key comparison function. I think this would be the simplest option.
To use a std::list, you can write your own comparison code inside of the addThing() function that goes through the list looking at each string and inserts the new one at the appropriate place.

Related

c++ extract member of a key of a std::multiset into a std::vector without having a getter

I encountered the problem during an interview. I had to create a multimap which had as keys objects with one private member(a string, the name of the object) and mapped value ints(not relevant). There was one restriction imposed by the person leading the interview: there should be not get or set functions associated to the member string of the object. After some processing of the multimap with STL functions(like removing some elements), the following was requested: to extract the name of the key objects into a vector while removing any duplicates. I do not know how to extract the name of the key objects without having a get function(I could remove the duplicates once the extraction is performed). The person leading the interview brought into discussion functors and possibility to use a functor which could be a friend of the Object class.
Please let me know if you have any idea how this could be solved!
I provide bellow a simplified version of the code creating the multimap.
class Object
{
std::string m_name; /* no set or get function allowed */
public:
Object(std::string name): m_name(name) {}
friend bool operator< (const Object& o1, const Object& o2)
{
return o1.m_name.compare(o2.m_name) < 0;
}
};
void testMap()
{
std::multimap<Object, int> m1;
m1.insert(std::make_pair(Object("abc"), 1));
m1.insert(std::make_pair(Object("qwerty"), 2));
m1.insert(std::make_pair(Object("def"), 3));
m1.insert(std::make_pair(Object("qwerty"), 4))
/* extract Objects names in a vector while removing duplicates without adding a get m_name function */
}
Please let me know if you have any idea how this could be solved! I do not know how to access m_name which is private without a get function...
Not a nice solution, but using the fact that m1.begin() will always point to the alphabeticly first element we can decide if a given string would be the first in it, by inserting it to the map, and erasing it after the check. So we can start a binary-search caracter by character for the first string. Using this we can extract all keys from the map (by removing the already ones we find). I know this solution is a bit unortodox, and making a getter (or a friend function/class what is effectively a getter) is way better, but this can be done without modifying the class.
bool is_first(std::string s,std::multimap<Object,int>& m){
auto it=m.insert(std::make_pair(Object(s), -1));
bool res=it==m.begin();
m.erase(it);
return res;
}
bool eq(const Object&a,const Object& b){
return (!(a<b)) && (!(b<a));
}
std::string get_first(std::multimap<Object,int> m){
int len=0;
std::string res;
while (1){
char mn=-128,mx=127,mid;
res+=mn;
while(mn+1!=mx){
mid=(mn+(int)mx)/2;
res[len]=mid;
if (is_first(res,m)){
mn=mid;
}else{
mx=mid;
if (eq(m.begin()->first,Object(res)))
return res;
}
}
res[len]=mn;
++len;
}
}
void testMap()
{
std::multimap<Object, int> m1;
m1.insert(std::make_pair(Object("abc"), 1));
m1.insert(std::make_pair(Object("abc"), 1));
m1.insert(std::make_pair(Object("qwerty"), 2));
m1.insert(std::make_pair(Object("def"), 3));
m1.insert(std::make_pair(Object("qwerty"), 4));
while (!m1.empty()){
std::string s=get_first(m1);
std::cout<<s<<" ";
m1.erase(s);
}
}
The motto for this solution: "If it stupid but it works, then it isn't stupid"
If the interviewer mentioned "to use a functor which could be a friend of the Object class," this implies that you are allowed to modify class Object by adding a friend declaration. In that case, you can simply add a friend function (I don't see why a Functor would be better) like
class Object
{
std::string m_name; /* no set or get function allowed */
public:
Object(std::string name): m_name(name) {}
friend bool operator< (const Object& o1, const Object& o2)
{
return o1.m_name.compare(o2.m_name) < 0;
}
friend std::string name(const Object& o)
{
return o.m_name;
}
};
I cannot be sure, though, that the interviewer had this in mind; as #NathanOliver mentioned, there is a template trick to access a private member, but I cannot imagine that someone would ask that at an interview.

C++ unordered_map<string, ...> lookup without constructing string

I have C++ code that investigates a BIG string and matches lots of substrings. As much as possible, I avoid constructing std::strings, by encoding substrings like this:
char* buffer, size_t bufferSize
At some point, however, I'd like to look up a substring in one of these:
std::unordered_map<std::string, Info> stringToInfo = {...
So, to do that, I go:
stringToInfo.find(std::string(buffer, bufferSize))
That constructs a std::string for the sole purpose of the lookup.
I feel like there's an optimization I could do here, by... changing the key-type of the unordered_map to some kind of temporary string imposter, a class like this...
class SubString
{
char* buffer;
size_t bufferSize;
// ...
};
... that does the same logic as std::string to hash and compare, but then doesn't deallocate its buffer when it's destroyed.
So, my question is: is there a way to get the standard classes to do this, or do I write this class myself?
What you're wanting to do is called heterogeneous lookup. Since C++14 it's been supported for std::map::find and std::set::find (note versions (3) and (4) of the functions, which are templated on the lookup value type). It's more complicated for unordered containers because they need to be told of or find hash functions for all key types that will produce the same hash value for the same text. There's a proposal under consideration for a future Standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0919r0.html
Meanwhile, you could use another library that already supports heterogenous lookup, e.g. boost::unordered_map::find.
If you want to stick to std::unordered_map, you could avoid creating so many string temporaries by storing a std::string member alongside your unordered_map that you can reassign values to, then pass that string to find. You could encapsulate this in a custom container class.
Another route is to write a custom class to use as your unordered container key:
struct CharPtrOrString
{
const char* p_;
std::string s_;
explicit CharPtrOrString(const char* p) : p_{p} { }
CharPtrOrString(std::string s) : p_{nullptr}, s_{std::move(s)} { }
bool operator==(const CharPtrOrString& x) const
{
return p_ ? x.p_ ? std::strcmp(p_, x.p_) == 0
: p_ == x.s_
: x.p_ ? s_ == x.p_
: s_ == x.s_;
}
struct Hash
{
size_t operator()(const CharPtrOrString& x) const
{
std::string_view sv{x.p_ ? x.p_ : x.s_.c_str()};
return std::hash<std::string_view>()(sv);
}
};
};
You can then construct CharPtrOrString from std::strings for use in the unordered container keys, but construct one cheaply from your const char* each time you call find. Note that operator== above has to work out which you did (convention used is that if the pointer's nullptr then the std::string member's in use) so it compares the in-use members. The hash function has to make sure a std::string with a particular textual value will produce the same hash as a const char* (which it doesn't by default with GCC 7.3 and/or Clang 6 - I work with both and remember one had an issue but not which).
In C++20, you can now do this:
// struct is from "https://www.cppstories.com/2021/heterogeneous-access-cpp20/"
struct string_hash {
using is_transparent = void;
[[nodiscard]] size_t operator()(const char *txt) const {
return std::hash<std::string_view>{}(txt);
}
[[nodiscard]] size_t operator()(std::string_view txt) const {
return std::hash<std::string_view>{}(txt);
}
[[nodiscard]] size_t operator()(const std::string &txt) const {
return std::hash<std::string>{}(txt);
}
};
// Declaration of map
std::unordered_map<std::string, Info, string_hash, std::equal_to<>> map;
std::string_view key = "foo";
if (map.find(key))
{
// do something here
}
Just note that you will still need std::string when using []. There may be a way around that, but I'm not too sure

Sorting vector of instances

I am currently taking a coding class at university and they have VERY specific requirements for the homework assignments.
For this week we have a class called Npt that represents a Nobel Prize winner. This class contains, amongst other things, the Name, the year of the prize and the field of the winner.
Now we should make another class, Nobelpreise, that contains a container for instances of said Nobel prize winner class. We are supposed to sort the elements of that container by the year of the Nobel Prize.
I wasn't able to use the std::sort function with a custom comparator correctly. This is what my code roughly looks like:
class Nobelpreise
{
private:
int numb;
vector<Npt> xx;
public:
Nobelpreise(){numb=0;}
void add(Npt &n1){xx.push_back(n1);numb++;return;}
Npt get_nobel(int i) {return xx[i];}
vector<Npt> get_xx() {return xx;}
int get_numb(){return numb;}
~Nobelpreise(){}
bool mycomp(Npt N1, Npt N2) {return (N1.get_jverl()<N2.get_jverl());}
};
The method get_jverl() comes from the Npt class and just returns the year.
Now the sort function always gives back an error saying that:
sort(Npl.get_xx().begin(), Npl.get_xx().end(), Npl.mycomp)
requires two arguments. Shouldn’t they be provided by the sort function?
I have also tried to overload the < operator which does not seem to work either.
edit1: added end() and removed the () from Npl.mycomp
edit2: we are required to make the comparator function a member of the class
Make your method mycomp static, and write a method which does the sort job.
class Nobelpreise
{
private:
int numb;
vector<Npt> xx;
public:
Nobelpreise(){numb=0;}
~Nobelpreise(){}
vector<Npt>& get_xx() {return xx;}
static bool mycomp( const Npt &N1, const Npt &N2 ) { return N1.get_jverl() < N2.get_jverl(); }
//^^^^^^
void Sort() { std::sort( xx.begin(), xx.end(), &mycomp ); }
};
The method Npt::get_jverl has to be const
returntype get_jverl() const { return ...; }
If you do the sorting outside your class note that you have to return a reference to your vector in your method: vector<Npt>& get_xx() {return xx;}
sort(Npl.get_xx().begin(), Npl.get_xx().end(), &Nobelpreise::mycomp)
Firstly, we'll fix the error that you're fetching two instances of the list:
sort(Npl.get_xx().begin(), Npl.get_xx().end, Npl.mycomp());
Replace with
auto v = Npl.get_xx();
std::sort(v.begin(), v.end(), Npl.mycomp());
I've added () to v.end, too, as we want to call it. However, we don't mean to call Npl::mycomp() here - std::sort wants to receive a function, not the return value:
auto v = Npl.get_xx();
std::sort(v.begin(), v.end(), Npl::mycomp);
This still won't work, as Npl::mycomp is an instance method, and std::sort won't call it with an object pointer for this. As it's implementation doesn't use this, it can be made a static method. Better still, it doesn't use any of the private members, so can be made a free function, outside of any class:
// I've renamed this to say what it does
bool year_precedes(const Npt& a, const Npt& b) {
return a.get_jverl() < b.get_jverl();
}
class Nobelpreise; // make the full declaration available
// for the following to compile
// I've made this a nonmember, too, as it only uses public methods
vector<Npt> sorted_prizes(const Nobelpreise& p)
{
auto v = p.get_xx();
std::sort(v.begin(), v.end(), year_precedes);
return v;
}
That should be enough to help you on your way.
You didn't say which version of C++, but assuming C++11 here's a more modern approach (compared to the two answers that are already here). Your requirements don't mention needing the comparator for anything else, so rather than write a comparator, you can do this:
std::sort(Npl.get_xx().begin(), Npl.get_xx().end(), [](const Npt& lhs, const Npt& rhs) {
return lhs.get_jverl() < rhs.get_jverl()
});
You could put this code in the Sort method of the Nobelpreise class as Rabbid suggests.
Compared to the other approaches here, I'd argue it makes the code more readable as you can see inline what is being compared, instead of having to jump to a new function just to read one more line of code (assuming of course that function is not being used anywhere else). It also makes the code faster because you are passing a lambda rather than a function pointer, but you shouldn't necessarily worry about that at this stage.

C++: Immutable method versions

In C++11, what is the best way to provide two versions of a method, one to modify the object itself and one to return a modified copy?
For example, consider a string class which has the "append(string)" method. Sometimes you might want to use append to modify your existing string object, sometimes you might want to keep your string object the same and create a copy.
Of course, I could just implement the first version and manually create a new object everytime I need one but that adds multiple temporary variables and lines of code to my project.
If it is still not clear what I am trying to do:
String s1("xy");
String s2 = s1.appendCopy("z");
s1.appendThis("w");
// s1 == "xyw"
// s2 == "xyz"
In Ruby there is a concept (or rather, a naming convention) which says for such methods, there are two variants: append (creates a new String) and append! (modifies this object)
C++ does not have something like this, so I would be stuck with ugly method names like "appendCopy".
Is there a good way to implement what I am trying to do?
So far, the best idea I had would be to make the modifying versions class members and the copying/immutable versions static methods which take the object to work on as a const argument.
There is actually a guideline, expressed by Herb Sutter in GotW #84:
Prefer non-member non-friend functions.
In your specific case, append (in-place) requires modifying the existing string so is well-suited to be a class-method, while append (copying) does not, so (following the guideline) should not be a class-method.
Thus:
void std::string::append(std::string const&);
inline std::string append(std::string left, std::string const& right) {
left.append(right);
return left;
}
After popular request, here are two overloads that can be used to optimize performance. First the member-version that may reuse its argument's buffer:
void std::string::append(std::string&& other) {
size_t const result_size = this->size() + other.size();
if (this->capacity() < result_size) {
if (other.capacity() >= result_size) {
swap(*this, other);
this->prepend(other);
return;
}
// grow buffer
}
// append
}
And second the free-function that may reuse its right-hand buffer:
inline std::string append(std::string const& left, std::string&& right) {
right.prepend(left);
return right;
}
Note: I am not exactly sure there are not ambiguous overloads manifesting. I believe there should not be...
With the new move semantics you can write:
class A{
public:
// this will get the property
const dataType& PropertyName() const { return m_Property; }
// this wil set the property
dataType& PropertyName() { return m_Propery; }
private:
dataType m_Propery;
};
main()
{
A a;
a.PropertyName() = someValueOfType_dataType; // set
someOtherValueOfType_dataType = a.PropertyName(); // get
}

Find array element by member value - what are "for" loop/std::map/Compare/for_each alternatives?

Example routine:
const Armature* SceneFile::findArmature(const Str& name){
for (int i = 0; i < (int)armatures.size(); i++)
if (name == armatures[i].name)
return &armatures[i];
return 0;
}
Routine's purpose is (obviously) to find a value within an array of elements, based on element's member variable, where comparing member variable with external "key" is search criteria.
One way to do it is to iterate through array in loop. Another is to use some kind of "map" class (std::map, some kind of vector sorted values + binarySearch, etc, etc). It is also possible to make a class for std::find or for std::for_each and use it to "wrap" the iteration loop.
What are other ways to do that?
I'm looking for alternative ways/techniques to extract the required element.
Ideally - I'm looking for a language construct, or a template "combo", or a programming pattern I don't know of that would collapse entire loop or entire function into one statement. Preferably using standard C++/STL features (no C++0x, until it becomes a new standard) AND without having to write additional helper classes (i.e. if helper classes exist, they should be generated from existing templates).
I.e. something like std::find where comparison is based on class member variable, and a variable is extracted using standard template function, or if variable (the one compared against "key"("name")) in example can be selected as parameter.
The purpose of the question is to discover/find language feature/programming technique I don't know yet. I suspect that there may be an applicable construct/tempalte/function/technique similar to for_each, and knowing this technique may be useful. Which is the main reason for asking.
Ideas?
If you have access to Boost or another tr1 implementation, you can use bind to do this:
const Armature * SceneFile::findArmature(const char * name) {
find_if(armatures.begin(), armatures.end(),
bind(_stricmp, name, bind(&string::c_str, bind(&Armature::name, _1))) == 0);
}
Caveat: I suspect many would admit that this is shorter, but claim it fails on the more elegant/simpler criteria.
Sure looks like a case for std::find_if -- as the predicate, you could use e.g. a suitable bind1st. I'm reluctant to say more as this smacks of homework a lot...;-).
Why 5 lines? Clean doesn't have a number attached to it. In fact, clean code might take more lines in the utility classes, which can then be reused over and over. Don't restrict yourself unnecessarily.
class by_name
{
public:
by_name(const std::string& pName) :
mName(pName)
{}
template <typename T>
bool operator()(const T& pX)
{
return pX.name == pName;
}
private:
std::string mName;
};
Then:
const Armature* SceneFile::findArmature(const char* name)
{
// whatever the iterator type name is
auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
return iter == armatures.end() ? 0 : &(*iter);
}
Within restriction:
class by_name { public: by_name(const std::string& pName) : mName(pName) {} template <typename T> bool operator()(const T& pX) { return pX.name == pName; } private: std::string mName; };
Then:
const Armature* SceneFile::findArmature(const char* name)
{
// whatever the iterator type name is
auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
return iter == armatures.end() ? 0 : &(*iter);
}
:)
C++0x has ranged-based for-loops, which I think would make the most elegant solution:
const Armature* SceneFile::findArmature(const std::string& pName) const
{
for (auto a : armatures)
{
if (a.name = pName) return &a;
}
return 0;
}
You would probably need to use STL map. It gives you possibility to get the element using keys. Your key would be the name of armature.
http://www.cplusplus.com/reference/stl/map/
EDIT: :D
one liner B-)
const Armature* SceneFile::findArmature(const Str& name){for (int i = 0; i < (int)armatures.size(); i++) if(name == armatures[i].name) return &armatures[i]; return 0;}
Holy shiz, you're using _stricmp? FAIL. Also, you didn't actually tell us the type of the vectors or any of the variables involved, so this is just guesswork.
const Armature* SceneFile::findArmature(const std::string& lols) {
for(auto it = armatures.begin(); it != armatures.end(); it++) {
if (boost::iequals(lols, (*it).name))
return &(*it);
return NULL;
}
Ultimately, if you need this, you should put the armatures or pointers to them in a std::map. A vector is the wrong container if you're searching into it, they're best for when the collection is what's important rather than any finding behaviour.
Edited to use a std::string reference.