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.)
Related
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.
Let's say I have an object which may not be properly initialized, but it's not simply a null pointer to object; it's an object with empty or uninitialized members. But I want to check it in as readable a manner as if it was a pointer:
if (Object) use(Object);
For example, Object may have an int field which, if 0, is considered uninitialized. Then, I can make an overload of the ! operator like this:
bool operator!() const {return intField == 0;}
I can use it like so:
if (! Object) initialize (Object);
The thing is, if I want to test for the opposite condition (non-null-ness), I can't do just this:
if (Object)...
I only find awkward possibilities:
if (! (! Object))... // awful
if (Object.notNull()) // not so bad
The one closest to my wishes is confusing:
bool operator()() {return intField != 0;}
if (Object())... // it looks a lot like an argument-less constructor
AFAIK, there is no bool-returning empty operator (something like bool operator() {...}) or any other trick or idiom that can achieve this.
Any ideas of a readable solution other than the notNull() method? Thanks.
You can provide a type conversion operator, to allow conversion to bool:
explicit operator bool() const {return intField != 0;}
This allows it to be used in boolean contexts, such as if conditions. explicit is optional, but a good idea to prevent potentially confusing conversions to numeric types.
An alternative approach is to use Boost.Optional or similar, to make any type nullable.
I think you want to be careful by using operator overloading to indicate validity or an initialized state--especially if you will ever hold a pointer or reference to an object of this type.
For this case, I would recommend the following explicit notation:
if (Object.isValid()) use(Object);
This way, it's obvious to the next person who reads your code exactly what you're doing here. Operator overloading should always be obvious to the person using it, and a true/false check on an object means it exists or not, not necessarily if it's valid or not.
Is it possible to overload operators in such a way that you can capture a specific combination of them? For example lets say I have a custom object myObject of type MyType where [] is already overloaded to pass such calls down to a map object. That said, in the case of the following code:
int value = myObject["someProp"];
I'm already overloading [] but in this case I'd like to know when [] is being called on the object in an assignment, with a reference to the type of object that the property lookup is to be assigned to. This way I can cast the value coming out of the dynamic property lookup and so on and so forth. Any input is appreciated!
For more insight into exactly what I'm trying to accomplish, see this related question of mine.
No, you can't overload on the return type, or on the context in which the call appears (e.g. in an assignment etc).
You could, however, return a proxy object that would have a bunch of overloaded conversion operators. Without seeing what you intend to do, it's hard to say how far you might be able to get with this approach, or whether it's even a sane thing to do.
If you want type deduction for things like this, your best bet is to overload operator() instead, and pass in the thing you're going to be assigning to as a dummy parameter, i.e.:
MyType myObject;
int value = myObject("someProp", value);
I've made something like this work pretty well in the past. In particular, see e.g.:
https://github.com/sgolodetz/hesperus2/blob/master/source/engine/core/hesp/objects/base/ObjectManager.tpp
In principle, it's rather straightforward to do: all that is needed is
for your operator to return a proxy which then overloads the operators
you want to catch. In practice, it can cause more than a few problems;
readers will expect (a op1 b) op2 c to have
the same semantics as T tmp(a ip1 b); tmp op2
c. There are some common exceptions, however:
The operator[] in a multi-dimensional array will often return a
proxy which defines an operator[] itself, in order to support [][]
correctly.
More generally, a container which for whatever reasons needs to know
when a value is modified will have an operator[] which returns a
proxy; within the proxy, assignment is defined as setting the value in
the owning container, and there will be a convertion operator to the
value type, for use in rvalue contexts. Of course, this means that
things like m[i][j].funct() don't work; typically, however, this sort
of thing is used for matrices of numeric types, where member functions
aren't that relevant.
In contexts where it is desirable to support overload resolution based
on the target type (your example), the function can return a proxy with
overloaded conversion operators. You want to be extremely careful with
this—overloaded conversion operators are often a recipe for
overload resolution ambiguities&rdash;but there are enough exceptions
that this situation bears mentionning. (Important, here, is that the
results of the operator will amost always be used to intialize or to
assign to a specific object, the type of which determines which
conversion operator will be called.)
BTW: I might mention that in the example you give, there is no
assignment; it is a classical initialization. In this case, defining
the operator[] to return a proxy which defines operator int() const
would do the trick very well. Before going this route, however, you
should very definitely consider all of the use cases of your class, and
ensure that there are none in which the actual target type is ambiguous.
The other answers are basically correct that you can't do it. aix hints at a solution of a custom return type with overloaded conversion operators, but rightly indicates it isn't a sane thing to do. I've ventured down this path quite often and ultimately implicit conversions, and sequences of conversions, and ambiguities will bite you in you in the behind.
I've had a need of this quite often though. Ultimately I end up going for a series of overloaded functions, or templates, depending on your needs, perhaps like this:
void lookup( int& v, char const * name );
void lookup( double& c, char const * name );
In the template case I created global converters and did the below member function:
template<T>
void lookup( T&v, char const* name ) { v = convert<T>( get(name) ); }
If you want to keep the return value as the lookup you'll have to explicitly call a templated function.
template<T> T get( char const * name ) { ... }
//use
int a = obj.get<int>( "name" );
double b = obj.get<double>( "floaty" );
No, you can't do that.
Moreso, madness that way lies!
I am following a book to learn C++ (come from a python background). I've written this, which works:
class CatalogueItem
{
public:
CatalogueItem();
CatalogueItem(int item_code, const string &name, const string &description);
~CatalogueItem() {};
bool operator< (const CatalogueItem &other) const;
...
private:
...
};
...
list<CatalogueItem> my_list;
// this is just me playing around
CatalogueItem items[2];
items[0] = CatalogueItem(4, string("box"), string("it's a box"));
items[1] = CatalogueItem(3, string("cat"), string("it's a cat"));
my_list.push_back(items[0]);
my_list.push_back(items[1]);
my_list.sort();
The part I'm trying out is using the operator < to allow the list to sort itsself.
This all seems good, but http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Operator_Overloading seems to suggest avoiding doing this, which is exactly what the book says to do! ("In particular, do not overload operator== or operator< just so that your class can be used as a key in an STL container; instead, you should create equality and comparison functor types when declaring the container.")
I understand "create equality and comparison functor types" to mean creating comparison functions, like the below one:
bool my_comparison_function(const CatalogueItem &a, const CatalogueItem &b)
{
// my comparison code here
}
Is that what the style guide is referring to?
Does anyone have an option as to which method is more "correct"?
J
A functor type would be more like this:
struct CatalogueItemLessThan
{
bool operator()(const CatalogueItem &a, const CatalogueItem &b)
{
}
};
Then the usage would look like this:
list<CatalogueItem> my_list;
// this is just me playing around
CatalogueItem items[2];
items[0] = CatalogueItem(4, string("box"), string("it's a box"));
items[1] = CatalogueItem(3, string("cat"), string("it's a cat"));
my_list.push_back(items[0]);
my_list.push_back(items[1]);
my_list.sort(CatalogueItemLessThan());
The main advantage of this, is that is allows you to decouple sorting from the object itself. You can now provide as many types of sorting as you want, and use them in different places. (For example, string can be sorted in lexical order, or case-insensitively, or "naturally".
The advantage of using a functor as opposed to a loose function is that you can pass parameters into the comparison to modify how the functor should behave.
In general, the Google style-guide is not really the best style guide out there (IMHO especially their taking exception to exceptions, but that's another discussion). If an object has an obvious sorting order, I often add in a default operator<. If later, there are extra sort orders I want to add, then I add in loose functions. If at a later time, I need to add parameters to the sort order, then I make them into functors. There's no sense in adding in complexity before it's needed.
What Google is trying to say to you is the following.
As you know, you can overload one and only one operator '<' for a given type. Let's say it works for you. But imagine that in the future you might need to sort objects of the same type in accordance with some other comparison criterion. How are you going to do that? The only available version of '<' is already taken.
Of course, you can do that by writing a new named comparison function/functor (not the '<' operator) and explicitly supplying it to the sorting algorithm. You can write 2, 5, 10 more of them. You can write as many as you want. It will work. However, at that point there will be an obvious asymmetry in your code. One comparison function is implemented as 'operator <'. The others - as different named functions/functors. Is there a good reason for this asymmetry?
Well, there might be. If you have a very well-defined and obvious natural sorting method that applies to your type, it makes a very good sense to implement it as operator '<'. This would be the main comparison method. And other, auxiliary, less "natural" comparison methods can and should be implemented as named functions. This is prefectly fine.
However, what if you don't have such an obvious candidate for the "natural" comparison? In this case favoring one method over the other and "wasting" the '<' operator on an arbitrarily chosen one is not a good idea. In this case it is recommended to leave the '<' alone, and stick to named functions/functors instead.
In other words, by overloading the '<' you create a "favorite" comparison for the given type. If that's what you really want - go ahead and do it. But keep in mind that in many cases creating an artificial and arbitrary "favorite" is not a good idea. Don't rush the process of choosing that favorite. Don't take the '<' too early.
A functor type is a C++ type (class or struct), that overloads the () operator so that instances of the type behave like a function. This is similar to a class implementing __call__() in Python.
Some STL collection types like std::map require a key_compare functor to order the keys in interal tree structures and thus providing fast access times. By default, this is std::less, which uses operator< to compare values. Therefore this operator is often provided to allow custom classes to act as keys in std::map (and similar).
Google obviously discourages this in favor of supplying your own comparison functor. So, instead of implementing operator<, you could do the following:
struct my_compare
{
bool operator ()(const CatalogueItem& lhs, const CatalogueItem& rhs)
{
...
}
};
If you must access private members to implement this, declare the functor as a friend of your class.
I'm trying to create a "sparse" vector class in C++, like so:
template<typename V, V Default>
class SparseVector {
...
}
Internally, it will be represented by an std::map<int, V> (where V is the type of value stored). If an element is not present in the map, we will pretend that it is equal to the value Default from the template argument.
However, I'm having trouble overloading the subscript operator, []. I must overload the [] operator, because I'm passing objects from this class into a Boost function that expects [] to work correctly.
The const version is simple enough: check whether the index is in the map, return its value if so, or Default otherwise.
However, the non-const version requires me to return a reference, and that's where I run into trouble. If the value is only being read, I do not need (nor want) to add anything to the map; but if it's being written, I possibly need to put a new entry into the map. The problem is that the overloaded [] does not know whether a value is being read or written. It merely returns a reference.
Is there any way to solve this problem? Or perhaps to work around it?
There may be some very simple trick, but otherwise I think operator[] only has to return something which can be assigned from V (and converted to V), not necessarily a V&. So I think you need to return some object with an overloaded operator=(const V&), which creates the entry in your sparse container.
You will have to check what the Boost function does with its template parameter, though - a user-defined conversion to V affects what conversion chains are possible, for example by preventing there being any more user-defined conversions in the same chain.
Don't let the non-const operator& implementation return a reference, but a proxy object. You can then implement the assignment operator of the proxy object to distinguish read accesses to operator[] from write accesses.
Here's some code sketch to illustrate the idea. This approach is not pretty, but well - this is C++. C++ programmers don't waste time competing in beauty contests (they wouldn't stand a chance either). ;-)
template <typename V, V Default>
ProxyObject SparseVector::operator[]( int i ) {
// At this point, we don't know whether operator[] was called, so we return
// a proxy object and defer the decision until later
return ProxyObject<V, Default>( this, i );
}
template <typename V, V Default>
class ProxyObject {
ProxyObject( SparseVector<V, Default> *v, int idx );
ProxyObject<V, Default> &operator=( const V &v ) {
// If we get here, we know that operator[] was called to perform a write access,
// so we can insert an item in the vector if needed
}
operator V() {
// If we get here, we know that operator[] was called to perform a read access,
// so we can simply return the existing object
}
};
I wonder whether this design is sound.
If you want to return a reference, that means that clients of the class can store the result of calling operator[] in a reference, and read from/write to it at any later time. If you do not return a reference, and/or do not insert an element every time a specific index is addressed, how could they do this? (Also, I've got the feeling that the standard requires a proper STL container providing operator[] to have that operator return a reference, but I'm not sure of that.)
You might be able to circumvent that by giving your proxy also an operator V&() (which would create the entry and assign the default value), but I'm not sure this wouldn't just open another loop hole in some case I hadn't thought of yet.
std::map solves this problem by specifying that the non-const version of that operator always inserts an element (and not providing a const version at all).
Of course, you can always say this is not an off-the-shelf STL container, and operator[] does not return plain references users can store. And maybe that's OK. I just wonder.