I want to use the boost map and the documentation says I need an equality function and a hash function. I think understand what they should do but since I can't find any examples I'm not sure how to do it so I am looking for a trivial example, like a point class with members x, y or something close.
Edit: Finally got it working. Wish I hadn't had to waste so much time for this. Thanks anyway guys.
#include <boost/functional/hash.hpp>
#include <boost/unordered_map.hpp>
#include <boost/foreach.hpp>
#include <iostream>
namespace test { // class whose source i can't edit
class point
{
public:
float x;
float y;
point() : x(0), y(0) {}
point(int x, int y) : x(x), y(y) {}
point(float x, float y) : x(x), y(y) {}
point(double x, double y) : x((float) x), y((float) y) {}
bool operator==(point const& other) const
{
return x == other.x && y == other.y;
}
};
}
namespace test { // my source file
std::size_t hash_value(point const &p) {
boost::hash<int> hasher;
return hasher(p.x) + hasher(p.y);
}
}
int main() {
boost::unordered_map<test::point, std::string> myMap;
test::point p1(1, 2);
myMap[p1] = "1"; //now it works
std::cout << myMap[p1] << std::endl;
return 0;
}
Equality and hash aren't too tough to define. Equality:
class Point {
int x, y;
bool operator==(const Point& p) {
return (x == p.x && y == p.y);
}
};
Hashing tends to involve specializing a function or class.
template<> class boost::hash<Point> {
public:
size_t operator()(const Point& p) {
return boost::hash<int>(p.x) + boost::hash<int>(p.y);
}
};
You may need to read up on the specifics of your hash_map implementation for details, and you may also want to define a different hash algorithm.
This is right from boost documentation...
class point
{
int x;
int y;
public:
point() : x(0), y(0) {}
point(int x, int y) : x(x), y(y) {}
bool operator==(point const& other) const
{
return x == other.x && y == other.y;
}
};
class point
{
...
friend std::size_t hash_value(point const& p)
{
std::size_t seed = 0;
boost::hash_combine(seed, p.x);
boost::hash_combine(seed, p.y);
return seed;
}
...
};
Related
I have a circle defined like so:
class Circle {
public:
int x;
int y;
int r;
Circle() : x(0), y(0), r(0) {}
Circle(int x, int y, int r) {
this->x = x;
this->y = y;
this->r = r;
}
double area() {
return PI * pow(r, 2);
}
};
I want to be able to add it to a set, based on the hash of its center (x and y)
What's the correct and idiomatic way of doing this in C++ 11?
My question is two-fold
(1) Is there a way I can ask C++ to hash it for me? In Kotlin, there is the notion of a dataclass which automatically hashes the class attributes. I am looking for something similar.
(2) If not, how do I hash it myself, and relatedly - what are operators I need to overload?
I want to be able to add it to a set, based on the hash of its center (x and y)
If you wan't to put your circle in the std::set, you don't need to provide a hash function. You need to provide it only if you'd like to use std::unordered_set or any other unordered associative container (more info in hash).
As it goes for the most idiomatic way of implementation, I would go with something like this (taken from the std::hash example):
#include <cmath>
#include <unordered_set>
#include <set>
class Circle {
public:
int x;
int y;
int r;
Circle() : x(0), y(0), r(0) {}
Circle(int x, int y, int r) {
this->x = x;
this->y = y;
this->r = r;
}
double area() {
return 3.1415 * pow(r, 2);
}
};
bool operator==(const Circle& lhs, const Circle& rhs) {
return lhs.x == rhs.x && lhs.y == rhs.y;
}
template<> struct std::hash<Circle> {
std::size_t operator()(Circle const& s) const noexcept {
std::size_t h1 = std::hash<int>{}(s.x);
std::size_t h2 = std::hash<int>{}(s.y);
return h1 ^ (h2 << 1); // or use boost::hash_combine (see Discussion) https://en.cppreference.com/w/Talk:cpp/utility/hash
}
};
int main() {
std::unordered_set<Circle> circles;
return 0;
}
Link to example
EDIT:
(1) Is there a way I can ask C++ to hash it for me? In Kotlin, there is the notion of a dataclass which automatically hashes the class attributes. I am looking for something similar.
There is hash function for the basic types (list is on std::hash). You need to provide hashing function for your custom type. You can take an inspiration from the cppreference or create an own hashing function.
Here, values of x and y is being tried to set through base class constructor.
But, the code is unable to do so.
#include <iostream>
class Point2d {
public:
double x;
double y;
Point2d() : x(0), y(0) {
}
Point2d(double x, double y) : x(x), y(y) {
}
void Show() {
std::cout << "(" << x << "," << y << ")\n";
}
};
class Vector2d : public Point2d {
public:
Vector2d():Point2d(){
}
Vector2d(double x, double y) : Point2d(x,y) {
}
Vector2d(Vector2d const& vec) : Point2d(vec){
}
void Set(double x, double y) {
Point2d::Point2d(x, y);
}
};
int main() {
Vector2d v;
v.Set(20, -39);
v.Show(); // prints '(0,0)' instead of '(20,-39)'
}
My target is to reuse base class constructor, and, overloaded assignment operators as much as possible.
I'm afraid your code won't even compile at
void Set(double x, double y)
{
Point2d::Point2d(x, y);
}
A constructor of a base class should be called at the beginning of the member initializer lists of a subclass constructor, not in a member function.
What you need is probably
class Point2d {
public:
double x;
double y;
Point2d() : x(0), y(0) {
}
Point2d(double x, double y) : x(x), y(y) {
}
void Show() {
std::cout << "(" << x << "," << y << ")\n";
}
Point2d& operator=(Point2d const& rhs)
{
this->x = rhs.x;
this->y = rhs.y;
}
};
class Vector2d : public Point2d {
public:
Vector2d():Point2d(){
}
Vector2d(double x, double y) : Point2d(x,y) {
}
Vector2d(Vector2d const& vec) : Point2d(vec){
}
/* also need to be overloaded in the subclass */
Vector2d& operator=(Vector2d const& rhs)
{
Point2d::operator=(rhs);
return *this;
}
void Set(double x, double y) {
*this = Vector2d(x, y);
}
};
int main() {
Vector2d v;
v.Set(20, -39);
v.Show();
}
Well, you're trying to construct the base class in the setter function, but the base class will already be constructed when the derived class is constructed. I would just set the x and y values of the base class in the setter.
So I have two different structs (a & b) with same variables and an overloaded = operator in struct b to convert a to b.
I want to be able to simple assign a vector of a to a vector b, but compiler gives me an error:
main.cpp|61|error C2679: binary '=' : no operator found which takes a right-hand operand of type 'std::vector<_Ty>' (or there is no acceptable conversion)|
I assumed that I already had the overloaded = operator and that it would simply iterate over vector a and use that = operator for each instance. How would I do this?
Here is the code:
#include <iostream>
#include <vector>
using namespace std;
struct a
{
int x, y;
a() {}
a(int _x, int _y)
{
x = _x;
y = _y;
}
};
struct b
{
int x, y;
b(){}
b(int _x, int _y)
{
x = _x;
y = _y;
}
b& operator=(const a& _a)
{
x = _a.x;
y = _a.y;
return *this;
}
};
int main()
{
a a_test(1,2);
std::vector<a> a_vec;
std::vector<b> b_vec;
for(int i = 0; i <10; i++)
{
a_vec.push_back(a_test);
}
/*
for(int i = 0; i<a_vec.size(); i++)
{
b_vec.push_back(a_vec[i]);
}
*/
b_vec = a_vec;
return 0;
}
The problem is that your operator= only works on individual elements, not on whole vectors.
You need to define a constructor that converts an A into a B.
Then you can use std::vector::assign rather than std::vector::operator=.
#include <iostream>
#include <vector>
using namespace std;
struct A
{
int x, y;
A(): x(0), y(0) {}
A(int x, int y): x(x), y(y) {}
};
struct B
{
int x, y;
B(): x(0), y(0) {}
B(int x, int y): x(x), y(y) {}
// need to construct B from A
B(const A& a): x(a.x), y(a.y) {}
B& operator=(const A& a)
{
x = a.x;
y = a.y;
return *this;
}
};
int main()
{
A a_test(1,2);
std::vector<A> a_vec;
std::vector<B> b_vec;
for(int i = 0; i <10; i++)
{
a_vec.push_back(a_test);
}
// b_vec = a_vec; // not like this
b_vec.assign(a_vec.begin(), a_vec.end()); // like this
return 0;
}
NOTE: I changed some of your names because the C++ standard says we should not begin variable names with the underscore '_'.
Even though a and b look identical, the compiler sees them as different types, even if a is convertible to b (or vice versa). Hence, vector<a> and vector<b> are completely unrelated, so you cannot assign one to the other, and the whole assignment fails to compile.
You can use an algorithm like std::copy,
std::copy(a_vec.begin(), a_vec.end(), std::back_inserter(b_vec));
Can anybody help me with the syntax of passing an array of classes
to another class. The syntax of passing an array of classes to another
class has got me beaten. class line tries to be initialised by an
array of points, but the prototype does not match.
#include <iostream>
using namespace std;
class point {
public:
point() {}
point(int x, int y) : X(x), Y(y) {}
void setXY(int x, int y) { X = x; Y = y; }
int getX() { return X; }
int getY() { return Y; }
private:
int X, Y;
};
class line {
public:
line(point *points, int); // Problem line.
private:
point *coords;
int numpoints;
};
int main() {
point points[3];
points[0].setXY(3, 5);
points[1].setXY(7, 9);
points[2].setXY(1, 6);
line l(points, 3); // Problem line.
return 0;
}
Error message:
cygdrive/c/Tmp/cc4mAXRG.o:a.cpp:(.text+0xa7): undefined reference to `line::line(point*, int)'
You need to define a constructor for your line class - you've only provided a declaration.
#include <iostream>
using namespace std;
class point {
public:
point() {}
point(int x, int y) : X(x), Y(y) {}
void setXY(int x, int y) { X = x; Y = y; }
int getX() { return X; }
int getY() { return Y; }
private:
int X, Y;
};
class line {
public:
line(point *points, int count)
: coords(points), numpoints(count) {}
private:
point *coords;
int numpoints;
};
int main() {
point points[3];
points[0].setXY(3, 5);
points[1].setXY(7, 9);
points[2].setXY(1, 6);
line l(points, 3);
return 0;
}
I'd recommend taking a look at the difference between definitions and declarations. Additionally, you should consider maintaining a std::vector<point> in your line class to manage the points. Your line class might then behave as:
#include <vector>
class line {
public:
line(std::vector<point> points)
: coords(points), numpoints(coords.size()) {}
private:
std::vector<point> coords;
int numpoints;
};
You didn't provide a definition for the constructor.
Try:
line(point *points, int np) : coords(points), numpoints(np) {}
Missing body of constructor "line".
You define prototype only.
I use the named constructor idiom to create objects, because I have lots of calls with identical parameters but the object shall be created differently.
The C++ FAQ tell us how to do this. It also tells us how to force objects being heap allocated. Yet it really fails to tell us how to use the named constructor idiom with the new operator.
Because new requires a constructor to be called we cannot directly call named constructors. So I found two workarounds to this problem:
I create an additional copy constructor and hope that optimizing compilers won't create a temporary object.
class point_t {
int X,Y;
point_t(int x, int y) : X(x), Y(y) { }
public:
point_t(const point_t &x) : X(x.X), Y(x.Y) { }
static point_t carthesian(int x, int y) { return point_t(x,y); }
static point_t polar(float radius, float angle) {
return point_t(radius*std::cos(angle), radius*std::sin(angle));
}
void add(int x, int y) { X += x; Y += y; }
};
int main(int argc, char **argv) {
/* XXX: hope that compiler doesn't create a temporary */
point_t *x = new point_t(point_t::carthesian(1,2));
x->add(1,2);
}
The other version is to create separate named constructors. Because function overloading doesn't work on return type I use two different names, which is ugly.
class point_t {
int X,Y;
point_t(int x, int y) : X(x), Y(y) { }
public:
/* XXX: function overloading doesn't work on return types */
static point_t carthesian(int x, int y) { return point_t(x,y); }
static point_t *carthesian_heap(int x, int y) { return new point_t(x,y); }
void add(int x, int y) { X += x; Y += y; }
};
int main(int argc, char **argv) {
point_t *x = point_t::carthesian_heap(1,2);
x->add(1,2);
}
Is there a prettier version that is equal to the example code?
You can avoid named constructor idiom for this completely, and do it using an additonal dummy enum parameter to select the constructor.
enum Carthesian {carthesian};
enum Polar {polar};
class point_t {
int X,Y;
public:
point_t(int x, int y) : X(x), Y(y) { } // may keep as a default
point_t(Carthesian, int x, int y) :X(x),Y(y){}
point_t(Polar, float radius, float angle)
: X (radius*std::cos(angle)), Y(radius*std::sin(angle)) {}
void add(int x, int y) { X += x; Y += y; }
};
int main(int argc, char **argv) {
point_t *x = new point_t(carthesian,1,2);
point_t *y = new point_t(polar,0,3);
x->add(1,2);
}
It is simple, portable, and the only overhead you will see is for the passing of the dummy enum values. In the rare case this overhead is too high for you it can be eliminated by wrapping a function call even when the construction itself is not inlined, as follows:
enum Carthesian {carthesian};
enum Polar {polar};
class point_t {
int X,Y;
void initCarthesian(int x, int y); // may be long, not inlined
void initPolar(float radius, float angle);
public:
point_t(int x, int y) : X(x), Y(y) { } // may keep as a default
point_t(Carthesian, int x, int y)
{initCarthesian(x,y);} // this is short and inlined
point_t(Polar, float radius, float angle) {initPolar(radius, angle);}
void add(int x, int y) { X += x; Y += y; }
};
Another approach is to use a derived class for construction. When using inner classes, it leads into quite a nice syntax I think:
class point_t {
int X,Y;
public:
struct carthesian;
struct polar;
point_t(int x, int y) : X(x), Y(y) { } // may keep as a default
void add(int x, int y) { X += x; Y += y; }
};
struct point_t::carthesian: public point_t
{
carthesian(int x, int y):point_t(x,y){}
};
struct point_t::polar: public point_t
{
polar(float radius, float angle):point_t(radius*std::cos(angle),radius*std::sin(angle)){}
};
int main(int argc, char **argv) {
point_t *x = new point_t::carthesian(1,2);
point_t *y = new point_t::polar(0,3);
x->add(1,2);
return 0;
}
You could write :
point_t *x = new point_t(point_t::carthesian(1,2));
It first calls carthesian() and then the copy-constructor.
Or, is there any problem in it? Perhaps, a bit slow?
By the way, there is one clear advantage in this code: the programmer can clearly see the new operator in his code (where he is using point_t written by someone else), so you can assume that its his responsibility to call delete once he is done with x.
Is this really a problem? In my experience classes tend to be either dynamically allocated most of the time or seldom, if at all. Classes that represent values, such as your point_t class here, belong to the second category, while classes that represent entities (i.e. something with identity) belong to the first one.
So my suggestion is to chose what you think is the best approach for each class and only provide that. Note that you could always return a small directly allocated object which has a private pointer to a larger one, as in the Handle-Body idiom.
On the other hand, other answers show how you may disambiguate among constructors that take arguments of the same number and types. In this line of thought, one alternative approach is to introduce specific types for the arguments as follows:
class radius_t {
float R;
public:
explicit radius_t(float r) : R(r) {}
operator float() const { return R; }
};
class angle_t {
float A;
public:
explicit angle_t(float a) : A(a) {}
operator float() const { return A; }
};
class point_t {
float X,Y;
public:
point_t(float x, float y) : X(x), Y(y) { }
point_t(radius_t radius, angle_t angle) :
X(radius*std::cos(angle)), Y((radius*std::sin(angle)) {
}
void add(int x, int y) { X += x; Y += y; }
};
int main(int argc, char **argv) {
point_t *x = new point_t(radius_t(1),angle_t(2));
x->add(1,2);
}
One approach that I haven't seen is overloading the constructor making the heap allocation use the last argument as an out one (Granted that the second function is not technically a constructor, it doesn't return an instance). The result would be something like (taken as base your second code fragment):
class point_t {
int X,Y;
point_t(int x, int y) : X(x), Y(y) { }
public:
/* XXX: function overloading doesn't work on return types */
static point_t carthesian(const int x, const int y) { return point_t(x,y); }
static void carthesian(const int x, const int y, point_t * & point) { point = new point_t(x,y); }
void add(int x, int y) { X += x; Y += y; }
void add(const point_t & point) { this->X += point.x; this->Y += point.y; }
};
int main(int argc, char **argv) {
point_t p1 = point_t::carthesion(1, 2);
point_t * p2;
point_t::carthesian(1, 2, p2);
p2->add(p1);
}
Can think of template allocator:
template<typename T>
struct Allocator : T
{
template<typename A1, typename A2>
Allocator(A1 a1, A2 a2) : T(a1, a2) {}
};
class point_t {
//...
template<typename T> friend struct Allocator;
};
int main(int argc, char **argv) {
point_t *x = new Allocator<point_t>(1,2);
x->add(1,2);
}
Now Allocator is friend of point_t. So it can access its private constructor. Also, you can add few more constructors like <A1, A2> inside Allocator to make it more generalized. Advantages are:
It doesn't look verbose.
You don't have to worry about compiler optimizations
The friendship is not exploited as, Allocator is a template
and we use it solely for heap allocation
Demo.