While doing some unit tests I want to be able to compare some pretty simple structs (they contain only public data members). I could write a operator== for all of them separately but it would be cumbersome and repetitive. So I decided to try to do this in a generic way. Yet there is a problem - some of them are not POD as some of their fields have non-POD type, let's say a std::list for an example.
struct NonPod {
std::list<int> lst;
};
struct NonPod2 {
std::list<NonPod> lst;
};
template<class T>
bool operator==(const T& lhs, const T& rhs) {
//what should I put here to make it work safely
//to compare NonPod with other NonPod
//ant NonPod2 with other NonPod2
}
AFAIK, to compare POD safely I could just use std::memcmp and it would be all fine. Is it possible to do generic operator== for non-POD types as well? If so, how?
Sadly, there is no way to do this in C++17 (or earlier). C++20 will allow you to add:
auto operator<=>(const class_name&) const = default;
to each class. This will give you all the comparison operators defined in the obvious way.
If the classes are being created by a code generator, then adding a comparison function should be easy.
Related
apologies in advance if this question is stupid but:
I have an interface:
template <class T>
class IEqualCompare {
public:
virtual bool IsEqual(const T b) = 0;
bool operator== (const T b) { return this->IsEqual(b); } //Both are implemented in cpp file
bool operator!= (const T b) { return !(this->IsEqual(b)); }
};
And a class:
class Dimentions : IEqualCompare<Dimentions> {
...
bool IsEqual(const Dimentions b) { //IsEqual logic for this specific class }
...
}
I would like to only implement IsEqual method for each child class of IEqualCompare, as the logic within the operator overloads (==, !=) is the same for any IEqualCompare derived class.
Up until now I have always simply defined both operator overrides as virtual and implemented them inside each class, but as the logic should be always the same I wanted to know if this is possible or is it bad programming.
Thanks in advance for any answers.
First of all, since comparison operators are usually not meant to modify compared objects, they (and IsEqual method) should be declared const as a general practice of const correctness. Among other things it helps programmers avoid mistakes of accidentally modifying objects during semantically non-modifying operations and helps optimizers produce more efficient binaries by utilizing more assumptions about code behaviour. Also, to avoid unnecessary copying the argument of operators should generally be taken by reference, in our case by const reference so that referenced object can't be modified.
Now, if you want to just automatically add equality comparison operators to derived classes based on their IsEqual method and not to use dynamic polymorphism/dispatch (it would be pretty pointless for CRTP base), there's no need to make IsEqual virtual, or even a member of base class at all. Derived type is provided as template parameter type T, so you statically know actual (dynamic) object type (this is the whole point of CRTP pattern you use), thus you can statically cast this pointer to T* and call non-virtual IsEqual method of T through resulting pointer avoiding the more costly virtual dispatch mechanism. Example:
template<typename T>
class AddEqualComparisons {
public:
bool operator==(const T& b) const { return static_cast<T*>(this)->IsEqual(b); }
bool operator!=(const T& b) const { return !static_cast<T*>(this)->IsEqual(b); }
};
class Dimensions : public AddEqualComparisons<Dimensions> {
bool IsEqual(const Dimensions& rhs) const {
// ...
}
};
Your solution is not necessarily bad, it is an application of the "template method" design pattern. It does read like C#/Java-style code to me, which is perhaps unconventional in C++ for this purpose.
The convention in C++ has been to just write each operator!= in terms of operator==. With compilers now supporting C++20, the complementary operator can be generated automatically, removing the need to write a trivial expression like !(x == y). Something like this is often all you need to make your class equality-comparable:
class Foo {
friend bool operator==(Foo const&, Foo const&) = default;
};
If the subobjects of the class (its base classes and member variables) are all equality_comparable, then the above syntax will produce a default comparison operator that compares the two sets of subobjects. You can of course create your own definition if you need to deviate from this.
Note that declaring the operator as a non-member friend function is just my preference, the member function syntax is equally valid.
I have many classes that use std::tie to make a tuple out of all the class attribute and use it to implement the == operator. They look like this:
class S
{
int number;
std::string text;
// and many other attributes...
auto tied() const noexcept { return std::tie(/* list all attributes here */); }
bool operator==(const S &o) const noexcept
{
return tied() == o.tied();
}
};
The classes have similar methods but very different attributes, so I want to create a base class they all inherit from and I want to include this bit of comparison in the base class.
However, since I can't define a virtual method returning auto, I'm struggling to write an abstract generic tied() method that should make a tuple out of all a derived class's attributes no matter how many of them or of which types they are.
Is this feasible?
Note: All attributes are either of trivial type or std::strings.
Is there a generic way to make a tuple out of all class attributes?
There is no way to generate a list of members. That is a language feature that requires more reflection capabilities than C++ has. At best you can have a macro that simultaneously generates the member declarations and the function generating the tuple. See Boost Fusion for an implementation of that idea.
Of course, you are not limited to the C pre processor for meta programming. You can use any langauge to generate C++ source if you don't mind complicating the build process.
I'm struggling to write an abstract generic tied()
There is no way to write a virtual member function that would return a different tuple for derived instances.
Is this feasible?
No.
and use it to implement the == operator.
Since C++20, you can use defaulted <=> to generate all comparison operators. Prior to that, you need the boilerplate.
If there is a bounded number of elements, you can use CRTP and https://stackoverflow.com/a/39779537/1774667 to find the number of elements.
Using structured binding you can then build a tuple out of them.
This can be written in the CRTP base.
template<class T>
struct implement_equals {
friend bool operator!=(implement_equals const& lhs, implement_equals const& rhs ) {
return !(lhs==rhs);
}
T const& self() const {
return *static_cast<T const*>(this);
}
friend bool operator==(implement_equals const& lhs, implement_equals const& rhs) {
constexpr std::size_t count = construct_airity<T>;
return make_tie_from<count>{}(lhs.self()) == make_tie_from<count>{}(rhs.self());
}
};
next write make_tuple_from.
template<std::size_t>
struct make_tie_from;
template<>
struct make_tie_from<1> {
template<class T>
auto operator()( T const& t ) const {
auto const&[e0] = t;
return std::tie(e0);
}
};
then write 20 of those.
There are libraries that do this already for you you can find with a bit of googling. None of them are perfect, and they all require that the thing you are making a tie of expose the data publicly.
If you want to hide that data, create a struct that contains the data publicly to get the tie, and expose some way for implement_equals to get access to that struct (friend, whatever).
In c++14 you cannot do even this crippled for of reflection.
You can write implement_equals, but you have to manually write the tie. It is better than a virtual function, however.
I'm trying to build a Graph Datastructure based on an already existing Datastructure (which I cannot modify and which is not a graph itself).
I think I have somewhat a grasp on how to build most of the structure concerning the graph itself, but right now I have to reference back to the original data structure for one little "compare" function and having a really hard time how to model that properly...
My vertices represent two different classes A and B of the original data structure, that have different member variables and no common ancestors. For an algorithm I have to check whether two vertices are compatible.
The rule is: an A-Vertex and an B-Vertex are always incompatible, but if both vertices represent the same type I have to check some specifics for the respective type.
So the base idea is roughly like this:
bool isCompatible(const Vertex& other){
// if this->data is of other type than other->data
// return false;
// else return compareFunction(this->data, other->data)
// where maybe one could overload that compare-function
// or make a template out of it
}
But I don't really know how to store the reference to data without making it really ugly.
Idea 1) Use a void pointer for data, have some variable to store the type and then cast the void pointer into respective type
-> would probably work but seems really dangerous (type-safety?) and really ugly (basically no reusability for the Graph structure if you ever wanna use it on other data). Seems a bit like the brute force approach.
Idea 2) Make an abstract data class that offers some "isCompatible(data)" function, and have wrapper-classes for A and B respectively that inherit from the abstract class and override that function. Inside the overridden function one could use dynamic_cast then and compare the objects.
-> still doesn't seem like good design, but should also work?
Idea 3) Make templates work? It's my first time working with C++ so I'm having a few problems wrapping my head around that properly.
I think something like the following should work for comparing:
template<typename T1, typename T2>
bool compare(T1 object1, T2 object2){
return false;
}
And then having instances for (A,A) and (B,B) that override this. For me this seems like the way to got for the comparison itself. But I don't really know how to manage the reference from Vertex to the Object without losing the Type. Any suggestions?
I'm open to any other suggestions as well of course.
edit: I'm using C++11 if that's of relevance.
If your data is either an A or a B, where those two types have nothing in common, then sounds like what you want is a variant data type. The C++ standard library doesn't have one yet, but you could use Boost's:
boost::variant<A, B> data;
A variant gives you type safety (which void* doesn't) and doesn't require you to have a common ancestor between the two types (which apparently are conceptually unrelated).
With a variant like the above, you can implement your comparison using binary visitation:
bool isCompatible(const Vertex& other) {
boost::apply_visitor(is_compatible(), data, other.data);
}
with:
class is_compatible
: public boost::static_visitor<bool>
{
public:
template <typename T, typename U>
bool operator()( const T &, const U & ) const
{
return false; // cannot compare different types
}
bool operator()( const A& lhs, const A& rhs ) const
{
// whatever A-specific comparison
}
bool operator()( const B& lhs, const B& rhs ) const
{
// whatever B-specific comparison
}
};
The standard library neglects to implement basic operations for std::set and std::map like
set<T> set<T>::getUnion(set<T> other)
and
bool map<K,V>::contains(K key)
I know there are verbose and/or indirect workarounds for these methods but if I want my code to be maximally readable and expressive, I'm going to have to inherit from the STL, write my own Set and Map classes, and implement them myself. And yes, I'm aware of the sermonizing against doing this but the fact is the STL is incomplete.
I've done this but now I can't initialize my new classes using, e.g.,
Set<int> s = {1,2,3,4};
How do I inherit these initializers from the std classes?
Despite the fact that publically inheriting from standard library containers is considered to be a bad idea, you can "inherit" the constructors:
template <typename T>
struct Set : std::set<T>
{
using std::set<T>::set; // "inherit" the constructors.
};
then
Set<int> s{1,6,4,3,3,9};
Note that a better approach might be to implement functions:
template <typename C>
bool contains(const C& container, const typename C::key_type& key)
{
return container.count(key);
}
and similarly for the union of sets.
For gcc 4.7.x, you have to call the initializer_list constructor for the set or map:
template <typename T>
class Set : public set<T> {
public:
Set(){
set<T>::set();
}
Set(initializer_list<T> iList) {
set<T>::set(iList);
}
};
Allowing
Set<int> s = {1,2,3,4};
But after much trial and error, I can't find a way to do this for std::map.
Also, it disables all the other constructors, requiring me to reimplement them, a task I'm not up to yet, so I'm just giving up on initializer lists for now. Anyone is welcome to submit an answer that reimplements all the constructors as Set and I'll choose it as the answer.
I use data structures, and I sort these data structures a lot. These data structures are holding pointers to objects, not directly the objects themselves. Now I can write a simple comparison functor, or function, to tell the sort algorithm how to sort the pointers:
struct Object_ptr_comparer {
bool operator()(const Object* first, const Object* second) {
return *first < *second;
}
};
And use for example std::sort:
Object_ptr_comparer comp;
std::sort(data_str.begin(), data_str.end(), comp);
The only problem with this solution that I have to write extra pointer comparator functor for any type of class. Yes, I could use inheritance and polymorphism to write only the comparator of some root class, but I don't want to. Is there any other smart way to do this?
What about a template?
struct ptr_comparer {
template<typename T>
bool operator()(const T* first, const T* second) {
return *first < *second;
}
};
used like this:
std::sort(data_str.begin(), data_str.end(), ptr_comparer());
That's what templates are for!
struct ptr_comparer {
template<class Object>
bool operator()(const Object* first, const Object* second) const {
return std::less<Object>()(*first, *second);
}
};
std::sort(data_str.begin(), data_str.end(), ptr_comparer());
Since I've templated the operator rather than specializing the comparer directly, the compiler can deduce the types, so we don't have to put the types directly.
I use std::less rather than operator<, because it safely compares pointers to pointers (like char**), rather than relying on Undefined Behavior. std::less falls back on operator<, so it doesn't add any complexity to calling code, and there should be no downside.
I'm certain this one compiles