I'm having some trouble defining hash and equality functions for objects. I'm using the objects as keys for std::unordered_map's. I have two keys aKey and unaccessibleKey. I can add an equailty operator overload to aKey, but I can't to unaccessibleKey because it's "unaccessible". I have tried doing the following, but I'm not sure if I'm using the right syntax for everything, and I don't know how to define an equality function for unaccessibleKey. Here's what I've tried:
struct aKeyHash
{
std::size_t operator()(const aKey& k) const
{
return k.getnonconstmem()->nonconstfunc();
};
}
struct unaccessibleKeyHash
{
std::size_t operator()(const unaccessibleKey& k) const
{
return k.noncostmem;
};
}
bool UnaccessibleEqualityFunction(const unaccessibleKey& p1, const unaccessibleKey& p2)
{???} //i dont know how to define this
std::unordered_map<aKey, std::unordered_map<unaccessibleKey, aValue, unaccessibleKeyHash, unaccessibleEqualityFunctions>, aKeyHash>
Am I doing this right (aside from the function that I don't know how to define)? As a side note, when I tried calling k.getnonconstmem()->nonconstfunction() I get an error.
It would be possible to use unaccessibleKey::nonconstmem as the key itself because it's actually a hashed int, but that may lead to complications later down the line that I don't want to deal with.
So my questions the are: 1. do I have the right syntax for the hashes, 2. how do I define the equality function, 3. why would I get the error with the const/nonconst mixing?
do I have the right syntax for the hashes
The hash structures themselves have correct syntax. Whether the definitions of the hash functions are correct, depends on the definition of the target types. In particular, if getnonconstmem() is a non-const function, then calling it on a const reference is ill-formed. You may only call const functions on const objects.
how do I define the equality function
Return true when the objects have equal logical state, and false otherwise. An example, which assumes that the state consists of a single member:
return p1.member == p2.member;
why would I get the error with the const/nonconst mixing?
The shown code is not sufficient to explain why there would be errors. You will get errors if you try to modify, or call non-const functions on const objects, or any object through pointer or reference to const.
Related
By this question I am also trying to understand fundamentals of C++, as I am very new to C++. There are many good answers to problem of sorting a vector/list of custom classes, like this. In all of the examples the signature of comparator functions passed to sort are like this:
(const ClassType& obj1, const ClassType& obj2)
Is this signature mandatory for comparator functions? Or we can give some thing like this also:
(ClassType obj1, ClassType obj2)
Assuming I will modify the body of comparator accordingly.
If the first signature is mandatory, then why?
I want to understand reasons behind using const and reference'&'.
What I can think is const is because you don't want the comparator function to be able to modify the element. And reference is so that no multiple copies are created.
How should my signature be if I want to sort a vector which contains pointers to objects of custom class? Like (1) or (2) (see below) or both will work?
vertor to be sorted is of type vector
(1)
(const ClassType*& ptr1, const ClassType*& ptr2)
(2)
(ClassType* ptr1, ClassType* ptr2)
I recommend looking through This Documentation.
It explains that the signature of the compare function must be equivalent to:
bool cmp(const Type1& a, const Type2& b);
Being more precise it then goes on to explain that each parameter needs to be a type that is implicitly convertable from an object that is obtained by dereferencing an iterator to the sort function.
So if your iterator is std::vector<ClassType*>::iterator then your arguments need to be implicitly convertable to ClassType*.
If you are using something relatively small like an int or a pointer then I would accept them by value:
bool cmp(const ClassType* ptr1, const ClassType* ptr2) // this is more efficient
NOTE: I made them pointers to const because a sort function should not modify the values it is sorting.
(ClassType obj1, ClassType obj2)
In most situations this signature will also work, for comparators. The reason it is not used is because you have to realize that this is passing the objects by value, which requires the objects to be copied.
This will be a complete waste. The comparator function does not need to have its own copies of its parameters. All it needs are references to two objects it needs to compare, that's it. Additionally, a comparator function does not need to modify the objects it is comparing. It should not do that. Hence, explicitly using a const reference forces the compiler to issue a compilation error, if the comparator function is coded, in error, to modify the object.
And one situation where this will definitely not work is for classes that have deleted copy constructors. Instances of those classes cannot be copied, at all. You can still emplace them into the containers, but they cannot be copied. But they still can be compared.
const is so you know not to change the values while you're comparing them. Reference is because you don't want to make a copy of the value while you're trying to compare them -- they may not even be copyable.
It should look like your first example -- it's always a reference to the const type of the elements of the vector.
If you have vector, it's always:
T const & left, T const & right
So, if T is a pointer, then the signature for the comparison includes the comparison.
There's nothing really special about the STL. I use it for two main reasons, as a slightly more convenient array (std::vector) and because a balanced binary search tree is a hassle to implement. STL has a standard signature for comparators, so all the algorithms are written to operate on the '<' operation (so they test for equality with if(!( a < b || b < a)) ). They could just as easily have chosen the '>' operation or the C qsort() convention, and you can write your own templated sort routines to do that if you want. However it's easier to use C++ if everything uses the same conventions.
The comparators take const references because a comparator shouldn't modify what it is comparing, and because references are more efficient for objects than passing by value. If you just want to sort integers (rarely you need to sort just raw integers in a real program, though it's often done as an exercise) you can quite possibly write your own sort that passes by value and is a tiny bit faster than the STL sort as a consequence.
You can define the comparator with the following signature:
bool com(ClassType* const & lhs, ClassType* const & rhs);
Note the difference from your first option. (What is needed is a const reference to a ClassType* instead of a reference to a const ClassType*)
The second option should also be good.
I have a class like
struct S {
bool foo(const AType& v) const {
return values.count(&v); // compile error due to the constness of v
}
private:
std::set<AType*> values;
};
This is a simplified version. In real code, foo does some complex things.
The code produces an error
invalid conversion from ‘const AType*’ to ‘std::set<AType*>::key_type {aka AType*}’
I think foo should take 'const AType& v' because it does not mutate v.
The type of the member variable 'values' can not be std::set<const AType*> because some methods of the struct S call non-const methods of the elements contained in 'values'.
I can cast constness of 'v' away:
bool foo(const AType& v) const {
return values.count((AType*) &v);
}
But I think this may not be a good solution in general.
What solution could I have?
template<class T>
struct const_ptr_compare:std::less<T const*> {
typedef void is_transparent;
};
std::set<AType*, const_ptr_compare<AType>> values;
and bob is your uncle.
I defined a comparator that can transparently handle T const* comparisons as well as T* comparisons. I then told std::set that it is transparent.
The is_transparent technique is a C++14 enhancement to std::set. Your compiler may already have support for it.
If you want to be able to pass in base-classes-of-T a bit more work needs to be done. You need a function object that tests its two arguments (each pointers to const) to see which is a base class of the other, and does a std::less<base const*>{}(lhs, rhs) using that base class. However, that is going further down the rabbit hole than we need to.
A C++11/03 approach could involve making the editable portions of AType mutable, and having a const AType* set. Failing that, a const_cast<AType*> is reasonable.
Please don't use a C-style cast: they are almost never required, and they can be accidentally too powerful.
The root of the problem is this:
The type of the member variable 'values' can not be std::set because some methods of the struct S call non-const methods of
the elements contained in 'values'.
You are not supposed to mutate the set key in any way.
You should be using a map, where the actual key parts are in the key and are const, and the mutating parts are in the value and are non-const.
If this is impractical for your design, I understand. The const_cast workaround will solve the issue. It feels inelegant, but that's because your usage of set is inelegant.
This is just one of the many problems of the const correctness concept: it doesn't scale by composition.
The casting solution is just ok, if you feel it's "dirty" in some way probably you're overestimating cleanness of the const concept.
Consider that defining special types for const_iterator and const_reverse_iterator was needed or that sometimes const correctness requires actual code duplication (e.g. in many cases for operator[]) or that if you've an object containing a non-const pointer you can mutate the pointed-to object freely and even delete it in const members.
Your cast doesn't look that bad in comparison :-)
If I remove the const from the function parameters clang throws an error. This error in combination with missing const only appear with ref variables. What's going on?
vector<string> v = {"the", "quick", "brown", "fox"};
bool compareWords(const string & s1, const string & s2)
{
return s1.size() < s2.size();
}
stable_sort(v.begin(), v.end(), compareWords);
Strictly speaking,
bool compareWords(string & s1, string & s2)
{
return s1.size() < s2.size();
}
should work. The only requirement for compareWords is that it should not modify the arguments.
Here's some info from http://en.cppreference.com/w/cpp/algorithm/stable_sort
The signature of the comparison function should be equivalent to the following:
bool cmp(const Type1 &a, const Type2 &b);
The signature does not need to have const &, but the function object must not modify the objects passed to it.
However, some compilers take that requirement to mean that the arguments should be either const & or simply objects.
It's to help you ensure that you don't modify the arguments to the comparator.
If you were to modify the elements being sorted during the sort operation then the comparator might return inconsistent results, which would break the sorting algorithm - with potentially unlimited ill effects ("undefined behavior").
By saying string & s1 as a parameter without the const implies that you will be changing the underlying value back in the calling function. However, that value is the return value of a function -- it's not stored anywhere, it can't be changed.
(OK, due to some compiler magic it is stored somewhere, but that location is not accessible to the calling function, so you are still implying you want to do something that you can't do)
According to the C++ Standard
It is assumed that comp will not apply any non-constant function
through the dereferenced iterator.
So to provide this restriction objects of dereferenced iterators are considered as const references.
I think I don't really understand what's behind references, and I'd be glad to learn more about those.
I'm writing a math "vector" Class to do basic linear algeabra for numerical simulation. I was using Eigen before i was convinced not to use external libraries anymore. My problem is pretty straightforward :
I declare vector and sets its 3 components of type Scalar (these are doubles). I can do math with my vectors as I overload operators, but this is beyond the scope of my question.
I want to access the i-th component of my object through the function call operator () as I was used with Eigen : myVector(0) = 0.0 ; or Scalar d = myVector(0)+1.0 ;
According to my understanding of references, this solution should be working :
class mtnVector {
public:
typedef double Scalar;
Scalar data [3];
(setters, math, etc...)
inline Scalar & operator() (const int i) const {
return data[i] ;
}
};
But g++ says that it doesn't like the way I implement it and comfirms I s*** at references :
Vector.h:185: error: invalid initialization of reference of type ?double&? from expression of type ?const double?
What's very strange from my point of view is that if the array containing the data is dynamically set (Scalar * data) (with new operator) at class construction, the code compiles fine. But I don't see the point of having dynamically set data holder.
I don't get neither the need of const to overload the function call operator but I accept it.
Your operator() is declared const. This means that calling the function should never end up modifying the object. That function returns a member of this object by non-const reference, which would allow whoever called operator() to modify the internals of the object. Obviously this would be silly, so the compiler just doesn't allow it. If you're going to return a reference to a member from a const member function, you need to make that reference const:
inline const Scalar& operator() (const int i) const {
return data[i] ;
}
You might want to provide both a const and non-const version of the function, one of which returns a const Scalar& and the other a Scalar& (this is how the standard library containers do it).
It seems strange that you'd want to use operator() for this. Your expression myVector(0) would look more natural as myVector[0], which you can achieve through overloading operator[] instead.
Also, you should ignore whoever convinced you that you shouldn't use external libraries. Eigen, in particular, is a very mature and thoroughly tested library. Unless you really have a good reason, you should be using it.
I have a class Table which has a member function std::vector<Attribute> attributeVec(); where Attribute is a seperate class.
I am working with code that would like to do something of the form
if (tableA.attributeVec() == tableB.attributeVec()){ ...
Where tableA and tableB are Table objects.
I'm getting a lot of weird compiler errors in Visual Studio 2012 that say things like
binary '==' : no operator found which takes a left-hand operand of type 'const DatabaseAPI::Attribute' (or there is no acceptable conversion)
So I believe the vectors cannot be compared like that. It would make my life easier if I could get this code to compile, but how could I do that? Can I define the operator? Do I need to rewrite some of the Attribute class so they can be compared?
Specifics: After writing an API, I was given a set of tests which, if reasonable, need to work. While I believe this at least makes unreasonable assumptions about my code (given my API), it wouldn't hurt to implement this in my code.
Thanks!
Vectors can be compared using ==, but their contained type (Attribute in this case) must have a comparison operator==. If you give that to the Attribute class, the comparison should work.
On an unrelated note, that his method
std::vector<Attribute> attributeVec();
is returning a copy of a vector. You have to think whether this is the behaviour you really want.
You need operator== implemented in your Attribute class:
class Attribute {
bool operator== (const Attribute& other) const {
// return true if *this == other, otherwise return false
}
}
BTW: As juanchopanza noticed, it is possible that you could return just a reference to the vector from your attributeVec() function, instead of a copy of it:
std::vector<Attribute>& attributeVec();
That would be more efficient and the comparison (using the operator==) in an expression:
o1.attributeVec() == o2.attributeVec()
still work OK.
The error is basically self explanatory, you need operator== on Attribute.
Take a look at std::equal; the second form allows you to specify your own comparison function.
Example:
bool compareAttributes (const Attribute &a, const Attribute &b) { /* ... */ }
// assumes attributeVec() returns a reference; if not, then remove '&'
const std::vector<Attribute>& attribsA = tableA.attributeVec();
const std::vector<Attribute>& attribsB = tableB.attributeVec();
if(attribsA.size()==attribsB.size() &&
std::equal(attribsA.begin(), attribsA.end(),
attribsB.begin(), compareAttributes))
{ /* ... */ }
Ideally, attributeVec() returns a reference to attribute vectors. If you cannot write it this way, then attribsA and attribsB should not be defined as references. (In this case, you might consider writing a comparison function for Table that does not require generating vectors of Attribute.)