Why isn't stl compare function a member? - c++

Just idly curious why the compare function for stl::sort can't be a static member?
I have a small little helper class foo that is declared and defined in a header, but now I have to create a foo.cpp file for the implementation of cmp() so it isn't multiply defined.
I also have to think of a suitably decorated name so fooCmp() doesn't clash with any other cmp().
Because it has no access to any member variables any compare operation that needs access to some other value (eg. sort by distance from foo.bar) needs the complex bind2nd call.

I am not sure what you are complaining about:
std::sort(begin,end) // use operator<
std::sort(begin,end,order) // Where order is a functor
So order can be:
A function
A static member function
Or an object that behaves like a function.
The following works for me:
class X
{
public: static bool diff(X const& lhs,X const& rhs) { return true;}
};
int main()
{
std::vector<X> a;
std::sort(a.begin(),a.end(),&X::diff);
}
But if the class has some natural ordering then why not just define the operator< for the class. This will allow you the access to the members and will behave nicely for most of the standard containers/algorithms that need to define an ordering.
class X
{
public: bool operator<(X const& rhs) const { return true;}
};
int main()
{
std::vector<X> a;
std::sort(a.begin(),a.end());
}

If you're concerned with a multiply defined compare function, try declaring the function with static linkage. Then the scope of the function does not extend past the compilation unit where it is found.
That said, your compare "function" need not be a function at all, but can instead be a function object. A function object is very much like a function but is implemented as an operator() that takes the appropriate parameters within a regular class. Since it's a regular class, you can pass constructor parameters to the class.
Here is a simple example:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class comparator {
public:
bool operator()(int a, int b) {
return a < b;
}
};
int main(int, char *[])
{
vector<int> a;
a.push_back(1);
a.push_back(3);
a.push_back(2);
sort(a.begin(), a.end(), comparator());
cout << a << endl;
}

actually sounds like the function was
declared in the class,
defined in the header but outside the class without inline linkage
ie something like:
class foo{
public:
static bool compare(const foo& lhs,const foo& rhs);
...
};
bool foo::compare(const foo& lhs,const foo& rhs){
...
}
instead of
class foo{
public:
static bool compare(const foo& lhs,const foo& rhs);
...
};
inline bool foo::compare(const foo& lhs,const foo& rhs){
...
}
the first of which will cause the function to be defined in every compilation unit that
#includes "foo.h"

Related

Can I call the subclass constructor from my superclass?

I want to know if I can return a subclass object through an overloaded operator from my superclass.
#include <stdio.h>
#include <iostream>
using namespace std;
struct AndSpecification;
struct Specification{
virtual bool is_satisfied(int i) = 0;
AndSpecification operator&& (Specification & other){
return AndSpecification(*this, other);
}
};
struct Specification1 : Specification{
int k;
Specification1(int k) : k(k){}
bool is_satisfied(int i){
if (i > k)
return true;
return false;
}
};
struct Specification2 : Specification{
int k;
Specification2(int k) : k(k){}
bool is_satisfied(int i){
if (i < k)
return true;
return false;
}
};
struct AndSpecification : Specification{
Specification& first;
Specification& second;
AndSpecification(Specification& first, Specification& second) : first(first), second(second){}
bool is_satisfied(int i) override{
return first.is_satisfied(i) && second.is_satisfied(i);
}
};
I think that the result is that I can't use the constructor of my subclass because it is not yet defined. The error messages are:
main.cpp: In member function ‘AndSpecification Specification::operator&&(Specification&)’:
main.cpp:20:56: error: return type ‘struct AndSpecification’ is incomplete
AndSpecification operator&& (Specification & other){
^
main.cpp:21:45: error: invalid use of incomplete type ‘struct AndSpecification’
return AndSpecification(*this, other);
Your incomplete forward class declaration cannot be used in this manner until the class is fully defined. Incomplete (forward) class declaration can be used in certain cases, but this is not one of them.
A C++ compiler reads the source in order, from start to finish. When it sees your operator, it has no idea what this mysterious class is, that it's returning. It has not been defined yet. It only gets defined later, in the header/source file.
You need to declare the class method, and then define it only after the class it's returning is fully defined:
// ...
struct Specification{
virtual bool is_satisfied(int i) = 0;
AndSpecification operator&& (Specification & other);
};
// After AndSpecification is declared, later:
inline AndSpecification Specification::operator&& (Specification & other){
return AndSpecification(*this, other);
}
As an alternative to inline, put the definition of the operator method into one of the translation units.
Whenever the compiler must know the size of a type, it must be defined. A declaration is not enough for constructing a type.
In your case, the simple fix is to make operator&& a free function and move it to the bottom:
AndSpecification operator&& (Specification & left, Specification & right){
return AndSpecification(left, r)ight;
}
In my opinion, free binary operators are better than member functions.
You've implemented an inline function definition before completing the definition of one of the classes you're using in the function. The compiler knows there's a struct AndSpecification but it doesn't know that the particular constructor you're using exists. Declare your method in the class but don't define it until after the definition of AndSpecification.
struct Specification{
virtual bool is_satisfied(int i) = 0;
AndSpecification operator&& (Specification & other);
};
struct AndSpecification : Specification { ... }
inline Specification::operator&& (Specification & other) {
return AndSpecification(*this, other);
}

How to properly rewrite with templates this C++ code that uses inheritance

I have a C++ code that currently looks like this: there is a class hierarchy to do perform some comparison and a list class that uses it. Which comparison operation to use is determined at runtime based on some schema object. Here is the structure:
class A{
bool doComparison(const string& s1, const string& s2) const=0;
}
class B: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
class C: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
template <class, S>
public FancyList{
shared_ptr<A> z_;
vector<S> v;
FancyList(shared_ptr<A> z) : z_(z);
void DoSmth(){
....
z_->doComparison(arg1, arg2);
}
}
typedef FancyList<string> FancyStringList;
// Determine which comparison to use at runtime
shared_ptr<A> c = nullptr;
switch(type):
case int:
c = make_shared<B>();
break;
case double:
c = make_shared<B>();
break;
FancyStringList l(c);
l.push_back("stuff");
C# used to be my main language so this code seemed ok to me. But I was told that the problem with this approach is that it uses virtual functions so there is a slight overhead in a method call. What is the proper C++-way of reorganizing this code so there is no need to have this class hierarchy and no need to use virtual functions?
Contrary to what you want, the overhead of virtual function is unavoidable because the decision of which actual function is called is made in runtime.
If the decision is always made in runtime, the compiler cannot hard-code the function call into the generated machine code. It has to be a indirect function call: to use a pointer to point to a function, and to dereference the pointer before the function call. Virtual function is just one way to do indirect function call.
Template is a way tell the compiler to generate code during compile-time. All template can do is to not introduce overhead when the decision is made during compile-time. It can't help you remove works that must be done in runtime.
If you are still interested in using template, you may consider having the comparator as a template parameter.
template <class T, class Comparator>
class MyList
{
std::vector<T> vec;
Comparator comp;
public:
void do_thing(const T& a, const T& b)
{
vec.push_back(a);
vec.push_back(b);
bool x = comp(vec[0], vec[1]); // for example
std::cout << x;
}
};
In the comparator class, overload the function call operator.
class Compare1
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs < rhs;
}
};
class Compare2
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs.size() < rhs.size();
}
};
int main()
{
MyList<std::string, Compare1> myli1;
myli1.do_thing("a", "b");
MyList<std::string, Compare2> myli2;
myli2.do_thing("c", "d");
}
You can even hide indirect function call behind comparator class. But it does not remove the overhead.
class A
{
public:
virtual bool doComparison(const std::string& s1, const std::string& s2) const=0;
virtual ~A() = default;
};
class PolymorphicComparator
{
private:
std::shared_ptr<A> comp;
public:
PolymorphicComp(std::shared_ptr<A> c) : comp(c) {}
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return comp->doComparison(lhs, rhs);
}
};

Hash function errors, c++

Here's the simple example class with hash function I wrote. Function maybe isn't most efficient one, but quality of hash function isn't relevant to me for now.
#include<iostream>
#include<unordered_set>
using namespace std;
class Class{
private:
int num;
public:
Class(int n){num=n;}
Class(){num=0;}
int getNum(){return num;}
friend bool operator==(const Class &k1, const Class &k2);
};
bool operator==(const Class &k1, const Class &k2){
return(k1.num == k2.num);
}
namespace std {
template <>
struct hash<Class>{
size_t operator()(const Class & c) const
{
return(31+c.getNum()*7);
}
};
}
void main(){
unordered_set<Class> set;
set.insert(Class(5));
set.insert(Class(55));
set.insert(Class(4));
set.insert(Class(123));
set.insert(Class(11));
for(unordered_set<Class>::iterator it = set.begin(); it!=set.end(); it++)
cout<<it->getNum()<< endl;
}
This worked fine when all fields of Class were public, but errors appear in hash function at return(31+c.getNum()*7); on c, because I can't call getNum() function. I don't know if there is any problem if in line size_t operator()(const Class & c) const I remove const, so object c is not const?
Also, in the last line, cout<<it->getNum()<< endl, there is error when accessing getNum() function. I don't know how to iterate over unordered_set set and to print num.
Your operator takes a const class but calls a non-const member function. To fix your issue declare getNum as const since it does not modify the class.
class Class{
private:
int num;
public:
Class(int n) : num(n) {}
Class() : num(0) {}
int getNum() const { return num;}
friend bool operator==(const Class &k1, const Class &k2);
};
In the above example also notice that I used member initializer lists to instantiate member variables. Also change the return type from void to int on main and I recommend either returning 0 or EXIT_SUCCESS from <cstdlib> at the end of main.

Custom comparison operator and custom class for std::set in C++

I would like to create a set containing the objects of my class, I have to determine a custom comparison. Unfortunately, everything I tried did not work.
class My_Class {
public:
char letter;
set<My_Class, compare> Children;
};
Ant then, the compare struct:
struct compare {
bool operator() (const My_Class& a, const My_Class& b) const{
return a.letter < b.letter;
}
};
How can I make this work please?
Currently, the issue displays that identifiers a and b are not declared.
You are trying to use compare structure inside My_Class, which uses My_Class in its method. It is not a trivial case, but forward declaration will help. So this should work:
class My_Class;
struct compare {
bool operator() (const My_Class &a, const My_Class &b) const;
};
class My_Class {
public:
char letter;
set<My_Class, compare> Children;
};
bool compare::operator() (const My_Class &a, const My_Class &b) const
{
return a.letter < b.letter;
}
Another alternative would be to pass comparator to std::set constructor, rather than specify it as a template parameter:
class My_Class {
public:
My_Class();
char letter;
set<My_Class> Children;
};
struct compare {
bool operator() (const My_Class& a, const My_Class& b) const{
return a.letter < b.letter;
}
};
My_Class::My_Class() : Children( compare() )
{
}
The problem with your code is that it is not guaranteed to compile. The problem is not the compare struct, so take that out of the picture. It is this:
class My_Class {
public:
char letter;
set<My_Class, compare> Children; // it is the set<My_Class> that is the problem
};
You are defining a std::set of My_Class before the definition of My_Class is known to the compiler. In other words, you're using an incomplete type within the std::set container. There is no guarantee that the code will compile, and even if it did, the behavior now is undefined.
If you want a container that works with incomplete types, you can use the Boost container types here:
http://www.boost.org/doc/libs/1_55_0/doc/html/container.html
Here is the description about Incomplete Types within the Boost documentation:
http://www.boost.org/doc/libs/1_55_0/doc/html/container/main_features.html#container.main_features.containers_of_incomplete_types

Why i need to use the const function in the Less Traits

why i need to use the const function in the less traits?
for example, why i must use const in Age or ID member function.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <string>
#include <set>
using namespace std;
class Person
{
public:
Person(int id, string name, int age):m_iID(id), m_strName(name), m_iAge(age){};
int Age() const {return m_iAge;}
int ID() const {return m_iID;}
void Display();
friend ostream& operator<<(ostream& out, Person& person);
private:
int m_iID;
string m_strName;
int m_iAge;
};
void Person::Display()
{
cout<<m_iID<<" "<<m_strName<<" "<<m_iAge<<endl;
}
ostream& operator<< (ostream& out, Person& person)
{
out<<person.m_iID<<" "<<person.m_strName<<" "<<person.m_iAge<<endl;
return out;
}
int SumPersonAge(int iSumAge, Person& person)
{
return iSumAge + person.Age();
}
template <typename Type>
void Display(Type t1)
{
cout<<t1<<endl;
}
class LessPerson
{
public:
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
};
int main()
{
set<Person, LessPerson> s1;
Person p1(1234, "Roger", 23);
Person p2(1235, "Razor", 24);
s1.insert(p1);
s1.insert(p2);
for_each(s1.begin(), s1.end(), Display<Person>);
}
if i remove the const the keyword in Age or ID function, the compiler will report me Error cannot convert 'this' pointer from 'const Person' to 'Person &'.
The answer is that the set will pass two const reference to Person objects to your comparator, and you cannot call a non-const function on a const variable.
You might be surprised as there seems not to be any const in the declaration of the functor:
struct LessPerson
{
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
};
But there is, it is just not explicit in the code. Inside the set implementation there are two const Person& references (call them r1, r2) and a LessPerson comparator (call it compare) and the code does something in the lines of if ( comparator(r1,r2) ). The compiler finds the templated operator() and tries to infer the types ending up with the type substitution: Type == const Person.
Why does the set use const references rather than plain modifiable references? Well, that is a different issue. The set is implemented as a sorted balanced tree, with each node containing the key. Now because a change in the key would break the order invariant, the keys are themselves const objects, ensuring that you cannot break the invariants.
That const keyword means that the function does not modify its object, this. Only const functions may be called from const objects. So, the compiler is telling you that you are trying to call a non-const member function from a const object.
You appear to be avoiding the const keyword, but it creeps in when the library calls your template function:
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
Type is passed as const Person.
const is not easy to get rid of without cheating, and it will always creep in. It's better to go with the flow and add const everywhere you take a reference that doesn't change an object (which is most of them).
Because the type passed to LessPerson is const Person.
So basically, LessPerson is roughly
class LessPerson   
{
public:
bool operator()(const Person& t1, const Person& t2)
{
return t1.ID() < t2.ID();
}
};
You can't call non-const methods on const objects. It's a rule of C++.