Comparing the value of template variable - c++

I'm writing a linked list for a C++ class and am stuck trying to figure out how to compare two generic typed nodes for a sorting algorithm. In Java I would just implement the Comparable interface and use the compareTo() method to determine which is "larger" or "smaller", letting the user of the Collection define this. Is there something similar in C++ that I can use? I know I can override the "<" operator but I don't know if this is the "best" method (subjective, I know; really just asking for pros and cons if there is another) to compare unknown types.
So, are there any other options to compare unknown types at runtime that seem to be more appropriate than overriding the "<" operator?
EDIT: Changed the operator I need to override.

From what I gather you have a list class template and you want to implement a sort() method on it. I would follow the example set by std::list<T> for this:
template <typename T>
class List
{
public:
// ...
template <typename Compare>
void sort(Compare compare) {
// use compare(x, y) to determine if x is smaller than y
}
void sort() { this->sort(std::less<T>()); }
};
That is, instead of making a fixed choice you would default to use operator<() but allow the user to use a different ordering predicate. As long as the comparison function implement a strict weak order anything can be used.

Yes, overloading operators (for sorting, you'd use operator< and maybe operator==) is the way. It's idiomatic and you needn't mark the interface (like deriving from a specific interface), and it is not typically done.
The good thing is that even if the user wanted to use some type without relation operators, he/she can extend their interface by providing free function overloads of the operators.
You could use any other method (such as inventing your own interface, eg. function int T::cmp(...) that would return 0/1/-1 depending on the relation of the parameters. However, this has the great disadvantage that you won't be able to reuse others' classes.
The STL uses a user-passed function object object to compare what it needs, which is needed to provide different sorting orders on the same data (say, ordering people by surname vs. by telephone number). If you don't need this (or are prepared to forgo this functionality), you can stick to using operator<.

Related

How do you check that a class/template implements a set of traits?

If I create a custom template or class that is supposed to implement a concept defined by a set of traits. How can I test that it actually does implement that concept?
Is there a generally accepted way of doing this for 'traits' classes?
(concepts in C++20 are the accepted way in
general but I am currently limited to C++14-ish)
Or is it just a case of having to remember?
Some related examples:
If I write a fancy pointer that I want to be sure implements pointer_traits. How can I check that it actually does?
If I write a custom allocator that I want to be sure implements allocator_traits. How can I check that it actually does?
How can I check I've properly implemented iterator_traits?
For example if I implement a 'fancy' pointer along the lines of boost::interprocess::offset_ptr:
I do the normal things:
implement & test constructors from T* T&
implement & test comparisons <=, <, !=, ==, >=, >=
implement & test dereferencing operator* & operator->
implement & test assignment
implement & test pointer arithmetic ++, --, -, +, +=, -=
To use this type with an allocator we need to implement pointer traits.
Is it just a case of implementing to_address() and pointer_to()?
You can make a pointer-like class which does not implement comparisons or pointer arithmetic.
Would that still be a valid model of pointer_traits?
This question suggests that a valid pointer must implement the random access iterator concept.
So the answer would seem to be no.
That question is also close to what I'm trying to do.
I expect there are two answers to this.
A concepts version and one for earlier iterations of C++. I am interested in both though I am currently limited to C++14.
There is the obvious answer which is to add a test which uses the thing you want to use.
So we add an allocator which uses the pointer and add a test using that allocator with an STL type.
This is useful and necessary but not necessarily complete or sufficient. It is also relatively speaking an integration test (does X work with Y) rather than a unit test (does X do what X should do).
It is very easy to miss something.
For example when implementing smart pointer comparisons it is easy to forget to make the following valid.
nullptr == smartPtr
Likewise I suspect there are some things that will work if some of the traits are implemented and others that won't if some a not implemented correctly.
Hence, I want to add a test or tests to the pointer class's testsuite to ensure it implements everything it needs to implemented to be used with the allocator template.
I also want to better understand what allocator traits, pointer traits and iterator traits are really doing.
Related reading:
http://blog.nuggetwheat.org/index.php/2015/09/01/why-pointer_traits-was-introduced-in-c11/ and links.
https://github.com/Quuxplusone/from-scratch/blob/master/include/scratch/bits/traits-classes/pointer-traits.md
Update 1
Speaking of missing things.
I already realised I need:
explicit operator bool () const;
bool operator! () const;
rebind
using iterator_category = std::random_access_iterator_tag;
Found by attempting to instantiate boost::containers::vector and std::vector.
There are some others I am still trying to sort out along with the rebind part.

Setting vector as a general parameter

So I've been trying to create a function that will receive vector objects as a general type in C++.
I have three classes Coffee, Snack, and Juice. And I have a binary search function to search for a specific item in each of the three vector objects created by those classes. But in order to do the binary search, I'd have to define three binary search functions. For example, binarySearchCoffee(vector coffeeList), binarySearchSnack(vector coffeeList) and the same for the Juice. So, is there a way to create a general vector type parameter that will take in whatever I inserted or is defining three functions ordinary? But I do not think so because it violates the DRY rule.
Thank you for your time.
This is what templates are for. Indeed, that's how the vector itself works!!
template <typename ElementType>
bool DoMyBinarySearch(const std::vector<ElementType>& container, const ElementType& value)
{
auto it = std::lower_bound(std::begin(container), std::end(container), value);
return it != std::end(container) && *it == value;
}
You might even consider making the container type the template argument, so that you're not restricted to vectors (though that may not be useful in this case).
This example also doesn't consider alternative allocators, or alternative comparators, which may or may not matter to you. cppreference.com's std::lower_bound article has a more robust example.
Don't forget to document the precondition that container must be sorted.

Most efficient way to process all items in an unknown container?

I'm doing a computation in C++ and it has to be as fast as possible (it is executed 60 times per second with possibly large data). During the computation, a certain set of items have to be processed. However, in different cases, different implementations of the item storage are optimal, so i need to use an abstract class for that.
My question is, what is the most common and most efficient way to do an action with each of the items in C++? (I don't need to change the structure of the container during that.) I have thought of two possible solutions:
Make iterators for the storage classes. (They're also mine, so i can add it.) This is common in Java, but doesn't seem very 'C' to me:
class Iterator {
public:
bool more() const;
Item * next();
}
Add sort of an abstract handler, which would be overriden in the computation part and would include the code to be called on each item:
class Handler {
public:
virtual void process(Item &item) = 0;
}
(Only a function pointer wouldn't be enough because it has to also bring some other data.)
Something completely different?
The second option seems a bit better to me since the items could in fact be processed in a single loop without interruption, but it makes the code quite messy as i would have to make quite a lot of derived classes. What would you suggest?
Thanks.
Edit: To be more exact, the storage data type isn't exactly just an ADT, it has means of only finding only a specific subset of the elements in it based on some parameters, which i need to then process, so i can't prepare all of them in an array or something.
#include <algorithm>
Have a look at the existing containers provided by the C++ standard, and functions such as for_each.
For a comparison of C++ container iteration to interfaces in "modern" languages, see this answer of mine. The other answers have good examples of what the idiomatic C++ way looks like in practice.
Using templated functors, as the standard containers and algorithms do, will definitely give you a speed advantage over virtual dispatch (although sometimes the compiler can devirtualize calls, don't count on it).
C++ has iterators already. It's not a particularly "Java" thing. (Note that their interface is different, though, and they're much more efficient than their Java equivalents)
As for the second approach, calling a virtual function for every element is going to hurt performance if you're worried about throughput.
If you can (pre-)sort your data so that all objects of the same type are stored consecutively, then you can select the function to call once, and then apply it to all elements of that type. Otherwise, you'll have to go through the indirection/type check of a virtual function or another mechanism to perform the appropriate action for every individual element.
What gave you the impression that iterators are not very C++-like? The standard library is full of them (see this), and includes a wide range of algorithms that can be used to effectively perform tasks on a wide range of standard container types.
If you use the STL containers you can save re-inventing the wheel and get easy access to a wide variety of pre-defined algorithms. This is almost always better than writing your own equivalent container with an ad-hoc iteration solution.
A function template perhaps:
template <typename C>
void process(C & c)
{
typedef typename C::value_type type;
for (type & x : c) { do_something_with(x); }
}
The iteration will use the containers iterators, which is generally as efficient as you can get.
You can specialize the template for specific containers.

Can we use a user defined class for the key in a STL map?

I need a key in the map, however, I found it should be multiple data. Can I put these data in one user defined class and put the whole class as a key in the map?
Will it impact the time efficiency?
What other concerns should be applied here?
Any type can be used as a key as long as it is
Copyable
Assignable
Comparable, since the map is sorted by key
If your class is just a simple structure, then it's already copyable and assignable. For a class to be comparable, you must either implement operator<, or create the map with a custom comparison function to use instead.
The only impact on time efficiency comes from larger objects taking longer to copy and compare. If the objects need to be that size, then there's nothing you can do about that, so don't worry about it.
As long as that class has an operator< (or otherwise make its instances <-comparable, e.g. by defining a free-standing operator< that can accept two such instances as arguments one way or another -- or, again, you make the map with an explicit comparison object), it will work fine. It will be fast if and only if that operator or function (and other crucial bits like its copy constructor) are, of course.
Edit: added the extra bit that operator< (if that's what you want to use rather than providing an explicit comparison object) need not be an operator, but could be a separate function -- tx to #Neil for pointing this out in a comment.
A type to be used as a map's key type either needs to have a std::less<T> specialization or another predicate (instead of the default std::less) passed to the map. The default implementation of std::less uses <. So you can
overload operator<() for your type
specialize std::less for it
pass different predicate to std::map.
Yes, you can use any class as the key as long as it implements the less-than operator< or you give a comparison trait in the map definition.
Don't worry about the time unless it proves to be a problem in practice.
Regarding using user defined classes for keys, sure. Because of the way Map is defined, your must define a 'less than' operator (operator<) for your class, or give a comparator object when constructing the map. Here's an example of the latter.
Regarding efficiency, don't worry prematurely, but one concern is how costly it is to make copies of the key object.
This is not about efficiency, but avoid altering the content of the keys in way that would affect the result of operator< while they're in the map.
If you're interested in efficient indexing with the different components of the key (since you say it is 'multiple data', look at boost::multi_index.
For sure you can ,you'll just need to overload the "<" operator in order to set a user defined key. An example:
struct x
{
int t;
bool operator<(const x &a) const
{ return (this->t < a.t); }
};
int main()
{
x p={10}, q={11}, r={12};
map<x,int> m;
m[p]=1; m[q]=2; m[r]=3;
for(auto w: m)
cout<<w.first.t<<" "<<w.second<<"\n";
}

Operator overload for [] operator

Why would you need to overload the [] operator? I have never come across a practical scenario where this was necessary. Can somebody tell me a practical use case for this.
Err.. std::vector<t>, std::basic_string<t>, std::map<k, v>, and std::deque<t> ?
I used this for a class representing a registry key, where operator[] returned an object representing a registry value with the string between []s.
See also, the Spirit Parser Framework, which uses [] for semantic actions.
Any indexable container can usefully define operator[] to become usable in any template that uses []-syntax indexing.
You don't need that syntax sugar if you're not doing generic programming -- it may look nice, but, cosmetics apart, you could always define specific named methods such as getAt, setAt, and the like, with similar and simpler-to-code functionality.
However, generic programming is at the core of modern C++... and it bears an eerie resemblance to "compile-time, type-safe duck typing" (I'm biased towards such peculiar terminology, of course, having had a part in shaping it -- cfr wikipedia;-).
Just as you should try to use, e.g., prefix-* to mean "dereferencing" for all kinds of iterators and other pointer-like types (so they can be duck-typingly substituted for pointers in a template!), so similarly you should strive to define operator[] in container types where it makes sense, just so they can be duck-typingly substituted for arrays in appropriate templates.
It is useful if you implement almost any type of container that provides random access (or at least some form of keyed access) to its elements (e.g., consider std::vector).
If you write a class that inherits from another class that implements the [] operator, you might want to overwrite the [] operator, such as std::vector or std::string. If you don't do this, your class may not work as the user expects, as your class will implicitly inherit the parent's implementation of [].
Well, several STL containers give some examples - vector<> overloads it to make it act like an array. map<> for example provides the operator[] overload to provide an 'associative array'.
While it is not strictly necessary, it is incredibly useful in making user-defined containers or strings behave like builtin arrays or C strings. This cuts down on verbosity a lot (for example, in Java, you would have to use x.getElementAt(i) while in C++ you can use x[i]; similarly, in Java you need x.compareTo(y)<0, while in C++ you can achieve the same thing using x < y). It is syntactic sugar... but it is very, very tasty.