I expected to be able to find a way to make the poly interface comparable, so one could compare the value stored in it. It's reasonably easy to add a way to check if the types are the same (by adding a function to make them return the type_index of type inside the poly), then return false in the comparison operator when they are not, but I've not been able to find a way to compare the same types by calling the operator== of the right one when those are the same. Example:
#include <iostream>
#include <typeindex>
#include "te.hpp"
using std::cout;
using std::endl;
namespace te = boost::te;
struct One {
bool operator==(const One&) const {
return true;
}
};
struct Two {
bool operator==(const Two&) const {
return true;
}
};
struct Comparable : te::poly<Comparable> {
using te::poly<Comparable>::poly;
bool operator==(const Comparable& other) const {
auto body = [](auto const& self, Comparable const& other) {
// `self` is the "downcast" type (One/Two), but `other` is
// Comparable, the interface. We need to figure out how to get the
// right type.
// This doesn't really work, as the types are never the same.
// if constexpr (std::is_same_v<decltype(self), decltype(other)>)
// return self == other;
// return false;
// This doesn't compile, as One or Two can (and should) only compare
// with themselves, but `other` is of type Comparable.
// return self == other;
const bool sameType = other.type() == std::type_index(typeid(self));
// Not ideal, as we know for sure that we are not the same when the
// type is not the same, but we don't know if two objects of the
// same type are the same. We need to cast `other` to the type of
// `self`. Now `other` is Comparable, while `self` is the "real"
// object put into a Comparable (e.g. One, Two).
// return sameType;
// The next lines are the further I've been able to get to.
if (!sameType)
return false;
// Attempt to cast `other` to the same type of `self`.
using SelfType = decltype(self);
auto innerBody = [] (auto const& innerSelf, const SelfType& innerOther) {
if constexpr (std::is_same_v<decltype(innerSelf), SelfType>)
return false;
else
return innerSelf == innerOther;
};
// Crashes. I tried to swap `other` and `self` with respect to the
// other te::call, so I could get the `Comparable const& other` cast
// to the right type inside the poly, and use the `operator==` of
// `One` or `Two`.
return te::call<bool>(innerBody, other, self);
};
return te::call<bool>(body, *this, other);
}
std::type_index type() const {
return te::call<std::type_index>([](auto const& self) {
return std::type_index(typeid(self));
}, *this);
}
};
int main()
{
Comparable one = One{};
Comparable two = Two{};
cout << one.type().name() << endl;
cout << two.type().name() << endl;
cout << "one==one " << (one == one) << endl;
cout << "one==two " << (one == two) << endl;
cout << "two==two " << (two == two) << endl;
}
Actual Behavior
With the code as in the cample above, it crashes at runtime, and I could not properly understand why.
Alternatively, I would consider that adding something like te::cast<T>, with a similar behavior as any_cast, would make sense. It would allow one to do the usual operations that one can do with std::any and "normal" polymorphism. The AnyAny library seems to provide that functionality (both the cast, and a default way to make the polymorphic value comparable via a built-in API for making it provide the operator).
Expected Behavior
I expected to be able to find a way to make the poly interface comparable, so one could compare the value stored in it. It's reasonably easy to add a way to check if the types are the same (by adding a function to make them return the
type_index
of type inside the poly), then return false in the comparison operator when they are not, but I've not been able to find a way to compare the same types by calling theoperator==
of the right one when those are the same. Example:Actual Behavior
With the code as in the cample above, it crashes at runtime, and I could not properly understand why.
Alternatively, I would consider that adding something like
te::cast<T>
, with a similar behavior asany_cast
, would make sense. It would allow one to do the usual operations that one can do withstd::any
and "normal" polymorphism. The AnyAny library seems to provide that functionality (both the cast, and a default way to make the polymorphic value comparable via a built-in API for making it provide the operator).Steps to Reproduce the Problem
Just trying the example above.
Specifications
Thank you!