I have two classes in library:
class A
{
public:
int x;
};
template <class T>
class B : public A
{
public:
T y;
};
And have method:
... Method(A &a, A &b);
How compare y from a and b if a, b always have same type
B <T>
, but type of T unknown?
When you have a function,
Method(A a, A b);
You have lost the B part of the objects due to object slicing.
If you want retain the B part of the objects, you have to use references or pointers.
Method(A const& a, A const& b);
or
Method(A const* a, A const* b);
In order for Method to work correctly, you have to provide a way for the objects to be treated as B. You can use that using a virtual function in A.
class A
{
public:
int x;
virtual int compare(A const& rhs) const
{
return (this->x - rhs.x);
}
};
and make sure to override the function in B.
template <class T>
class B : public A
{
public:
T y;
virtual int compare(A const& rhs) const
{
// Use the base class first.
int r = A::compare(rhs);
// If the base class result is adequate, return.
if ( r != 0 )
{
return r;
}
// Do a dynamic_cast of the rhs.
B const* rhsPtr = dynamic_cast<B const*>(&rhs);
// If the dynamic_cast didn't succeed, need
// to figure out how to handle the case.
if ( rhsPtr == nullptr )
{
// Add error handling code
}
return (this->y - rhsPtr->y);
}
};
Then, in Method,
Method(A const& a, A const& b)
{
int r = a.compare(b);
}
A possible solution is to create a virtual function that will do the comparison.
Inside the body of the implementation in the derived class the type T is known and you'll have no problems.
struct Base {
...
virtual bool same_y(const Base& other) const = 0;
};
template<typename T>
struct Derived : Base {
T y;
virtual bool same_y(const Base& other) const {
return dynamic_cast< const Derived<T>& >(other).y == y;
}
};
You could define Method as a template method.
template<typename T>
bool Method(const A& a, const A& b)
{
const B<T>& first = dynamic_cast<const B<T>&>(a);
const B<T>& second = dynamic_cast<const B<T>&> (b);
return first.y == second.y;
}
With this approach you don't have to know the type of T inside Method. But you have to specify T when you call it:
bool areEqual = Method<int>(a, b);
Maybe that is no problem in your case.
Be aware that whenever you assign a B<T> to a variable of type A you are loosing the information that is specific to B<T> (in this case the value of y is lost). That's why I changed the signature of Method in order to take references instead of values.
Related
I have a hash process implemented using Howard Hinnant's method (generic hash based on hash_append overloads).
The purpose of that method is to create hash of classes in order to "memoize" result of computations (see end of this answer), so I am facing some issue. In particular, consider the following possible Input class that needs to be hashed:
struct A {
virtual int do_stuff() const = 0;
virtual ~A();
};
struct B: A {
int do_stuff() const override { return 0; }
};
struct C: A {
const int u;
int do_stuff() const override { return u; }
};
struct Input {
A const& a; // store a reference to an instance of B or C
};
Now, if I want to hash Input, I will have something like:
template <class HashAlgorithm>
void hash_append(HashAlgorithm& h, Input const& input) {
hash_append(h, typeid(input));
hash_append(h, typeid(input.a));
}
So I need an overload of hash_append for A:
template <class HashAlgorithm>
void hash_append(HashAlgorithm& h, A const& a) {
hash_append(h, typeid(a));
}
The problem here is that depending on the runtime type of a, I would need to add extra information to the hash, e.g. for C I would need to add u.
I thought about the following solutions (and drawbacks):
add a virtual method to A that returns a specific value that can be added to the typeid() hash, but:
this means adding a method inside A that is not related to the purpose of A, thus I don't really like this idea (in particular because I have multiple A-like classes);
this breaks the concept of hash_append since the method will have a unique return type for all inheriting classes.
do a bunch of dynamic_cast inside hash_append:
I found this pretty ugly... in particular if I have multiple classes similar to A;
this is error-prone: if someone adds a new children of A and do not add a dynamic_cast inside hash_append.
Is there a way to hash a polymorphic type, without having to modify the type itself or rely on a bunch of dynamic_cast?
The final goal of this is to be able to memoize results of some heavy functions. Let's sketch the basic structure of my application:
struct Input { };
struct Result { };
Result solve(Input const&);
The solve function is computationally-heavy, so I want to save the results of previous computation in file using hash of Inputs, e.g. something like:
// depends on hash_append
std::string hash(Input const&);
Result load_or_solve(Input const& input) {
auto h = hash(input);
Result result;
if (exists(h)) { // if result exists, load it
result = load(h);
}
else { // otherwize, solve + store
result = solve(input);
store(h, result);
}
return result;
}
The load and store methods would load and store results from files, the goal is to memoize solutions between different runs.
If you have suggestion on how to memoize these results without having to deal with the above issues, I'll be glad to read them.
You can use double dispatching within the hash_append version of A and forward the request to the proper version (that is the one either for B or C). The drawback is that you must add boilerplate to those classes to accept a visitor and I cannot say if it's acceptable for you.
Here is a bunch of code that should illustrate the idea:
struct B;
struct C;
struct Visitor {
virtual void visit(const B &) = 0;
virtual void visit(const C &) = 0;
};
template<typename T, typename... O>
struct HashVisitor: T, HashVisitor<O...> {
template<typename U>
std::enable_if_t<std::is_same<T, U>::value> tryVisit(const U &u) {
T::operator()(u);
}
template<typename U>
std::enable_if_t<not std::is_same<T, U>::value> tryVisit(const U &u) {
HashVisitor<O...>::visit(u);
}
void visit(const B &b) override { tryVisit<B>(b); }
void visit(const C &c) override { tryVisit<C>(c); }
};
template<>
struct HashVisitor<>: Visitor {};
template<typename... F
auto factory(F&&... f) {
return HashVisitor<std::decay_t<F>>{std::forward<F>(f)...};
}
struct A {
virtual void accept(Visitor &) = 0;
virtual int do_stuff() const = 0;
virtual ~A();
};
struct B: A {
void accept(Visitor &v) override { v.visit(*this); }
int do_stuff() const override { return 0; }
};
struct C: A {
const int u;
void accept(Visitor &v) override { v.visit(*this); }
int do_stuff() const override { return u; }
};
template <class HashAlgorithm>
void hash_append(HashAlgorithm &, const B &) {
// do something
}
template <class HashAlgorithm>
void hash_append(HashAlgorithm &, const C &) {
// do something
}
template <class HashAlgorithm>
void hash_append(HashAlgorithm &h, const A &a) {
auto vis = factory(
[&h](const B &b){ hash_append(h, b); },
[&h](const C &c){ hash_append(h, c); }
);
a.accept(vis);
}
I have below as 'simple' of an example of what I am trying to do as I could think up. I have an abstract class A which exposes a public interface to the world with two methods: operator== and performTasksSpecificToA. You can see that I'm using the 'Template Method Pattern' as well as the 'curiously recurring template pattern' in order to ensure that users of A don't need to worry about the implementation of A, in other words AImpl, while still being able to check equality against two instances of AImpl. See this answer on SO for a bit more information and context on this approach.
Now, suppose I wish to define a class B as follows:
class B
{
public:
virtual ~B() = 0;
bool operator(const B& b) const;
void performTasksSpecificToB();
};
As you can see, class B shares the same problem as A in terms of defining a public operator== for comparing sub-classes. How can I define a parent-class, let's call it Letter, in order to avoid duplicating code between A and B?
Here is my 'simple example', which compiles and runs.
#include <iostream>
class A
{
public:
virtual ~A() = 0;
bool operator==(const A& a) const;
void performTasksSpecificToA();
private:
virtual bool checkEquality_(const A& a) const = 0;
};
template <class T>
class A_ : public A
{
protected:
bool checkEquality_(const A& a) const override;
private:
virtual bool checkEquality(const T& t) const = 0;
};
class AImpl : public A_<AImpl>
{
public:
AImpl(int val) : val(val){};
bool checkEquality(const AImpl& anAImpl) const override;
private:
int val;
};
A::~A(){}
bool A::operator==(const A& a) const{
return checkEquality_(a);
}
template <class T>
bool A_<T>::checkEquality_(const A& a) const{
const T* other = dynamic_cast<const T*>(&a);
if (other != nullptr){
const T& me = static_cast<const T&>(*this);
return other->checkEquality(me);
}
return false;
}
bool AImpl::checkEquality(const AImpl& anAImpl) const{
return val == anAImpl.val;
}
int main(){
// factory:
AImpl* aImpl1 = new AImpl(1);
AImpl* aImpl2 = new AImpl(2);
AImpl* aImpl3 = new AImpl(1);
// client:
A& A1 = *aImpl1;
A& A2 = *aImpl2;
A& A3 = *aImpl3;
std::cout << "A1 == A2 -> ";
std::cout << (A1 == A2 ? "true" : "false");
std::cout << std::endl;
std::cout << "A1 == A3 -> ";
std::cout << (A1 == A3 ? "true" : "false");
std::cout << std::endl;
delete aImpl1;
delete aImpl2;
delete aImpl3;
return 0;
}
If you can allow Letter to be a template, you can simply have A inherit from a template base:
template<class T>
class Letter
{
public:
bool operator==(const Letter<T>& t) const {
const T& t1 = static_cast<const T&>(*this);
const T& t2 = static_cast<const T&>(t);
return t1.checkEquality_(t2);
}
private:
virtual bool checkEquality_(const T& a) const = 0;
};
class A : public Letter<A>
{
public:
virtual ~A() = 0;
void performTasksSpecificToA();
};
...
If you absolutely need a common Letter, you probably have to add another layer of CRTP like you did with A_ and A.
It is possible to write a wrapper that takes any type that supports a certain operation, e.g.
#include <iostream>
class Houdini
{
struct I_Houdini_Impl
{
virtual void foo_impl(int x) const = 0;
virtual ~I_Houdini_Impl() { }
};
template <typename T>
struct Houdini_Impl : I_Houdini_Impl
{
Houdini_Impl(T const & t) : m_t(t) { }
void foo_impl(int x) const { m_t.foo(x); }
T m_t;
};
public:
template <typename T>
Houdini(T const & t) : m_impl(new Houdini_Impl<T>(t)) { }
void foo(int x) const { m_impl->foo_impl(x); }
protected:
private:
std::unique_ptr<I_Houdini_Impl> m_impl;
};
class A
{
public:
void foo(int x) const { std::cout << "A::foo(" << x << ")" << std::endl; }
};
class B
{
public:
template <typename T>
char foo(T const & t) const { std::cout << "B::foo(" << t << ")" << std::endl; return 'B';}
};
void houdini()
{
A a;
B b;
Houdini ha(a);
Houdini hb(b);
ha.foo(7);
hb.foo(8);
}
I can wrap anything in the Houdini-class that supports a const-method foo that can be called wih an int, regardless if it is an ordinary member function (as in class A) or a function template (as in class B) (and lets disregard for now that Houdini should exhibit value sematics). So far so good, but what I would like to do is to write a wrapper that supports binary operations, e.g. to write a wrapper that accepts any type and you can, say, add any two wrappers as long as the wrapped objects can be added and returns the wrapped return object from the addition:
class A { };
class B { };
class C { };
C operator+(A, B) { return C(); }
class Randi
{
public:
template <typename T> Randi(T ) { }
/* magic stuff goes here */
};
void randi()
{
A a;
B b;
Randi ra(a);
Randi rb(b);
Randi rc = ra + rb;
// rc is a Randi-object that wraps an object of type C
}
If I know in advance what types I am going to store I can do it by writing visitors but that is exactly what I do not want to do. I would need to unwrap both objects, try to call operator+ on the two unwrapped objects and wrap the result again but I cannot figure out how to do that.
Consider following
class Number
{
virtual Number* sum(Number* other) = 0;
};
class Int
: public Number
{
virtual Number* sum(Number* other)
{
// hard to implement since we doesn't know the type of other
}
};
class Double
: public Number
{
virtual Number* sum(Number* other)
{
// hard to implement since we doesn't know the type of other
}
};
We can do dynamic_casts in sum implementation to handle each case separately or we can use double dispatching.
class Double;
class Int;
class Number
{
public:
virtual Number* sum(Number* other) = 0;
protected
virtual Number* sum(Int* other) = 0;
virtual Number* sum(Double* other) = 0;
};
class Int
: public Number
{
virtual Number* sum(Number* other)
{
return other->sum(this);
}
virtual Number* sum(Int* other)
{
// implement int + int
}
virtual Number* sum(Double* other)
{
// implement int + double
}
};
class Double
: public Number
{
virtual Number* sum(Number* other)
{
return other->sum(this);
}
virtual Number* sum(Int* other)
{
// implement double + int
}
virtual Number* sum(Double* other)
{
// implement double + double
}
};
In bot cases implementations should be aware about all derived classes. This means that analog of Houdini_Impl for Randi class should know about all other types that may be passed to Randi's constructor which is impossible.
The title is a bit vague but I can't come up with a better wording, here's the deal:
class A
{
public:
A();
A( const PropertyB& b );
PropertyA GetPropertyA();
PropertyB GetPropertyB();
SetPropertyA( const PropertyA& b );
SetPropertyB( const PropertyB& b );
//assignment not allowed
};
Suppose I want to use an std::vector< A >, but, it only makes sense to have a vector of A if all it's elements have the same value for PropertyB. The current solutions is to supply a contrcutor-like method to create such array which guarantees all elements of the returned array have the same value for PropertyB, and a method that checks if that is the case:
Array MakeArray( size_t, const PropertyB& );
bool CheckIfArrayIsSane( const Array& );
So users can still call SetPropertyB() on the elements, but have a utility to check it and bail out if someone did:
Array x( MakeArray( 3, someValue ) );
x.SetPropertyA( aaa ); //should be allowed
x.SetPropertyB( someOtherValue ); //should NOT be allowed
//somewhat further in the program
if( !CheckIfArrayIsSane( x ) )
throw InsaneArrayExcpetion();
While this works, it's error-prone since it is hard to force this check everywhere and not forget it, and clutters the code with checks.
Approcahes that do not work:
Making SetPropertyB() private, and making MakeArray a friend function: then SetPropertyB() is not accessible anymore for users that simply want to use A without caring about the array.
Wrapping std::vector< A > in a seperate class and only returning const A& references: this would mean the other setters like SetPropertyA() can also not be called, but users should be able to call them. It's only SetPropertyB() that should be disallowed.
One more intrusive approach that would work but feels a bit unelegant, and needs extra functions to convert between the two etc:
class AWithFixedPropertyB
{
public:
A( const PropertyB& b );
PropertyA GetPropertyA();
PropertyB GetPropertyB();
SetPropertyA( const PropertyA& b );
};
class A : public AWithFixedPropertyB
{
public:
//contrcutors etc
SetPropertyB( const PropertyB& b );
};
//ok, users cannot modify property B in this Array
typedef std::vector< AWithFixedPropertyB > Array;
What would be the most elegant solution for this problem?
This doesn't make sense, from an OO design viewpoint. Remember the Liskov Susbsitution Principle: A is-a B whenever an A object can be used in the place of a B object? Per that rule, the elements of your proposed std::vector<A> fail the is-an-A test, since you can't set their B property. Yet std::vector<A> is supposed to be a container of A objects.
In C++ we have private inheritance, and this makes explicit that the derived class does not have an is-a relationship with its parent. You can use that as follows:
class A_fixed_B : private A
{
A_fixed_B(A const& src) : A(src) {}
A const& asA() const { return *this; } // Base Conversion is OK inside class.
using A::GetPropertyA;
using A::GetPropertyB;
using A::SetPropertyA;
};
You can now create a std::vector<A_fixed_B> which behaves as you'd probably expect.
The easier thing to do would be to wrap std::vector<A> and return some form of proxy object.
class WrappedVectorA : private std::vector<A> {
struct MyProxy {
MyProxy(A& ref) { ptr = &ref; }
A* ptr;
PropertyA GetPropertyA() const { return ptr->GetPropertyA(); }
PropertyB GetPropertyB() const { return ptr->GetPropertyB(); }
SetPropertyA( const PropertyA& b ) { return ptr->SetPropertyA(b); }
operator=(const A& a) { *ptr = a; }
operator const A&() const { return *ptr; }
operator A() { return *ptr; }
};
public:
MyProxy operator[](int index) {
return std::vector<A>::operator[](index);
}
const MyProxy operator[](int index) const {
return const_cast<A&>(std::vector<A>::operator[](index));
}
};
It's really kind of ugly, but it'll work. I guess you'd also need to wrap the iterators and at(). However, A itself doesn't need to know anything about this, and normal std::vector<A> are completely untouched.
I'll go with that :
class IA {
public:
virtual ~IA() {}
virtual PropertyA& GetPropertyA() = 0;
virtual void SetPropertyA(const PropertyA& a) = 0;
};
class A : public IA
{
public:
A();
A( const PropertyB& b );
PropertyA& GetPropertyA();
PropertyB GetPropertyB();
void SetPropertyA( const PropertyA& b );
void SetPropertyB( const PropertyB& b );
};
template< PropertyB value >
class fixedVector {
private:
std::vector<A> _tab;
public:
void pushback() {_tab.pushback(A(value)); }
IA& get(unsigned int i) { return _tab[i]; }
void popback() { _tab.pop_back(); }
};
If your A object are instanciate by a proxy, you could use a directly a std::vector< std::autoptr<AI> >;
Use a flyweight for the storage of PropertyB and throw an exception in SetPropertyB, if the count of elements in the flyweight is greater than 1 after the assignment.
Different PropertyBs will not be allowed no matter which container you store the As in.
#include <boost/flyweight.hpp>
class A
{
public:
A();
A( const PropertyB& b );
PropertyA GetPropertyA();
PropertyB GetPropertyB();
SetPropertyA( const PropertyA& b );
SetPropertyB( const PropertyB& b );
private:
PropertyA a;
boost::flyweights::flyweight<PropertyB> b;
};
A::SetPropertyB(const PropertyB& item)
{
b = item;
if(b.size() > 1) // you may have to implement flyweight::size() yourself
// should be able to do this based on core::factory().size();
throw InsaneArrayExcpetion();
}
Haven't actually tested if this code compiles, but it gives you the idea.
I would go with "Wrapping std::vector< A >..." approach. In that way user of the class will not be able to modify the objects in the vector where as if they want to call SetPropertyB they can create a copy of the object returned from this wrapper and use that method.
Use a policy base class to determine which fields can be set - this will generate a compile time error if you try to set the wrong property. The downside of course is that A is no longer simply A, but is typed on the policy.
Code:
#include <iostream>
#include <vector>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
class AllPolicy
{
public:
void setA(int a) { _setA(a); }
void setB(int b) { _setB(b); }
private:
virtual void _setA(int a) = 0;
virtual void _setB(int b) = 0;
};
class APolicy
{
public:
void setA(int a) { _setA(a); }
typedef void setB;
private:
virtual void _setA(int a) = 0;
};
class BPolicy
{
public:
void setB(int b) { _setB(b); }
typedef void setA;
private:
virtual void _setB(int b) = 0;
};
template <typename Policy>
class A : public Policy
{
public:
A(int a = 0, int b = 0) : _a(a), _b(b)
{
}
A(A const& v) : _a(v._a), _b(v._b)
{
}
~A() {}
A& operator=(A const& v)
{
_a = v._a;
_b = v._b;
return *this;
}
int getA() const { return _a; }
int getB() const { return _b; }
using Policy::setA;
using Policy::setB;
private:
virtual void _setA(int a) { _a = a; }
virtual void _setB(int b) { _b = b; }
private:
int _a;
int _b;
};
int main(void)
{
std::vector<A<AllPolicy> > all_v(1, A<AllPolicy>(2, 3));
all_v[0].setA(1);
all_v[0].setB(2);
std::vector<A<APolicy> > a_v(1, A<APolicy>(2));
a_v[0].setA(1);
a_v[0].setB(2);
std::vector<A<BPolicy> > b_v(1, A<BPolicy>(1, 3));
b_v[0].setA(1);
b_v[0].setB(2);
}
Demo: http://www.ideone.com/mTJSb
So the idea is to use inheritance and the base class of A will expose what can be set. In the AllPolicy case, both methods are exposed, and in the other case one or other of the setters are exposed. A compiler error should result (as in the demo) if you try to use the opposite setter to the policy. Of course now A<APolicy> is not the same as A<BPolicy>, and if you wanted conversion, you'll have to provide conversion constructors etc.
The problem is: I want to use unordered_map to store keys and values, where the key can be either class A or class B, depending on the users options. Both classes A and B inherit from the same class P.
class A: public P {...}
class B: public P {...}
I would like to define the map with the abstract P class and later, depending on runtime options, assign there a map with A or with B as a key:
unordered_map< P, CValue, P::hash, P::equal_to> * pmap = new unordered_map< A, CValue, A::hash, A::equal_to>;
but I will get error:
cannot convert ... in initialization
How can I declare such a "virtual" map?
Here's an example how you can make the map keyed on P* but still use different implementations in the derived classes:
struct P
{
virtual size_t hash_self() const = 0;
virtual bool equal(const P &) const = 0;
};
struct A : public P
{
inline bool operator==(const A & other) const { return false; /*Implement!*/}
size_t hash_self() const { return 1; /*Implement!*/ }
bool equal(const P & p) const { return *this == dynamic_cast<const A &>(p); }
};
struct PHash
{
size_t operator()(const P * const p) const { return p->hash_self(); }
};
struct PEqual
{
bool operator()(const P * const p, const P * const q) const { return p->equal(*q); }
};
#include <unordered_map>
std::unordered_map<P *, double, PHash, PEqual> pmap{{ new A, .5 }};
The dynamic cast is valid because you promise only to compare pointers of the same derived type.
If you wanted to be cleaner, you could probably specialise std::hash<P*> and std::equal_to<P*>:
namespace std
{
template<> struct hash<P*>
{ size_t operator()(P * const & p) const { return p->hash_self(); } };
template<> struct equal_to<P*> : public binary_function<P*, P*, bool>
{ bool operator()(P * const & p, P * const & q) const { return p->equal(*q); } };
}
std::unordered_map<P *, int> qmap{{new A, -11}}; // just works!
unsorted_map< P, CValue, P::hash, P::equal_to> * pmap = new unsorted_map< A, CValue, A::hash, A::equal_to>;
The type P is not same as type A.
So X<P> is a different type than X<A>. That means, this code
X<P> *pX = new X<A>();
wouldn't compile, even if A is derived from P. GCC would give this error (ideone):
error: cannot convert ‘X<A>*’ to ‘X<P>*’ in initialization
which is self-explanatory if you know that X<A> is a completely different type than X<P>.
Note that its A which is derived from P. But X<A> is still NOT derived from X<P>. I think you're confusing the latter with the former.
So what I think you need is this:
unorder_map<P*, P::hash, P::equal_to> objectMap;
You can insert object of type A* into this map:
objectMap.insert(new A());
You can insert object of type B* also:
objectMap.insert(new B());
After all, you want to treat all objects in the map polymorphically.