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.
Related
Let's suppose that we have 3 classes:
class A
{
public:
int a;
virtual ~A() = default;
};
class B : public A
{
public:
int b;
};
class C : public A
{
public:
int c;
};
And a vector that contains polymorphic objects derived from A
std::vector<A*> objects;
I want to have a template method, that will return me an object from vector of type gived in template, if that object exists, but I don't know how to write it..
This not work:
template<typename ComponentType>
ComponentType * GetComponent()
{
bool pred = std::find_if(objects.begin(), objects.end(),
[=](A * obj)
{
return
dynamic_cast<ComponentType*>(obj) != nullptr;
});
return pred != objects.end();
}
I know that it could be done with that code:
template<typename ComponentType>
ComponentType * GetComponent()
{
for (item : objects)
{
auto casted = dynamic_cast<ComponentType*>(item);
if (casted)
return casted;
}
return nullptr;
}
But I want to use lambda.
It does not work at least because std::find_if returns an iterator, not a bool.
You might change your solution to fix it and return either a pointer to the element or nullptr if there is no such element:
template<typename ComponentType>
ComponentType * GetComponent()
{
auto it = std::find_if(objects.begin(), objects.end(),
[](A * obj)
{
return dynamic_cast<ComponentType*>(obj) != nullptr;
});
return it != objects.end()
? dynamic_cast<ComponentType*>(*it)
: nullptr;
}
Note, that it is better to avoid dynamic_cast at all if it is possible. For example, you might add a virtual method to A class which identifies an object somehow, then override it in B and C and use to find a requested object.
In C++ I'm often facing a situation when I need to prepare const and non-const version of class in analogy to const_iterator and iterator from standard library.
class const_MyClass
{
public:
const_MyClass(const int * arr):
m_arr(arr)
{
}
int method() const; //does something with m_arr without modifying it
private:
const int * m_arr;
}
class MyClass
{
public:
MyClass(int * arr):
m_arr(arr)
{
}
int method() const; //does something with m_arr without modifying it
void modify(int i); //modify m_arr
private:
int * m_arr;
}
The problem with this is that I need to repeat whole code of const_MyClass in MyClass and distribute any changes in API to both classes. Thus sometimes I inherit const_MyClass and do some const_casts, which also isn't perfect and pretty solution. Still when I want to pass const_MyClass instance by reference it looks moronic:
void func(const const_MyClass & param)
Instance param is marked with two "consts", and it has only const methods...
This is where const constructors would be handy, but are there any existing alternatives?
Some use examples to explain problem better:
//ok to modify data
void f(int * data)
{
MyClass my(data);
my.modify();
...
}
//cant modify data, cant use MyClass
void fc(const int * data)
{
const_MyClass my(data);
int i = my.method();
...
}
You can make a template class to act as a base, like this:
template<typename T>
class basic_MyClass
{
public:
basic_MyClass(T * arr) :m_arr(arr) {}
int method() const; //does something with m_arr without modifying it
private:
T * m_arr;
};
Then, for your const version, since it doesn't add anything, you can just use a typedef:
typedef basic_MyClass<const int> const_MyClass;
For your non-const version, you can inherit:
class MyClass : public basic_MyClass<int>
{
public:
using basic_MyClass::basic_MyClass; // inherit all the constructors
void modify(int i); //modify m_arr
};
Have you considered simply tracking two pointers and raising exceptions from the mutable operations when no mutable value is available? Maybe an example will help describe what I am thinking of.
class MyClass
{
public:
MyClass(int *mutable_data):
m_mutable_view(mutable_data), m_readonly_view(mutable_data)
{
}
MyClass(const int *immutable_data):
m_mutable_view(NULL), m_readonly_view(immutable_data)
{
}
int retrieve_value(int index) {
return m_readonly_view[index];
}
void set_value(int index, int value) {
require_mutable();
m_mutable_view[index] = value;
}
protected:
void require_mutable() {
throw std::runtime_error("immutable view not available");
}
private:
const int *m_readonly_view;
int *m_mutable_view;
};
The idea is pretty simple here - use a sentinel value to indicate whether modifications are possible or not instead of depending on the type system to do that for you. Personally, I would think about doing the inheritance based approach that #BenjaminLindley suggested but I wanted to present a slightly different solution that might not have occurred to you.
After talk with Neil Kirk I realized what I was doing wrong. I started by separating data from logic as he suggested.
This attempt resulted in two classes MyClassPtr and const_MyClassPtr. They only provide functions for data access (like iterators) and may look like that:
class const_MyClassPtr
{
public:
const_MyClassPtr(const int * arr);
int operator [](int i) const;
const int * ptr() const;
private:
const int * m_arr;
}
class MyClassPtr
{
public:
MyClassPtr(int * arr);
int operator [](int i) const;
int & operator [](int i);
const int * ptr() const;
int * ptr();
//promotion to const pointer
const_MyClassPtr () const {return const_MyClassPtr(m_arr);}
private:
int * m_arr;
}
Now it is clear that objects of these classes should be treated like pointers, so when I use them as function parameters I pass them by value!
void func(const_MyClassPtr param) //instead of void func(const const_MyClass & param)
To provide methods I have created MyClassOp class template and used static polymorphism.
template <class DERIVED>
class MyClassOp
{
public:
const DERIVED & derived() const {return static_cast<const DERIVED &>(*this)}
DERIVED & derived() {return static_cast<DERIVED &>(*this)}
int method() const; //operates on derived() const
void modify(int i); //operates on derived()
}
MyClassOp is a collection of methods. It does not have state. In general it is a trait. To make these methods accessible I overloaded -> and * operators
class const_MyClassPtr : private MyClassOp<const_MyClassPtr>
{
public:
const MyClassOp<MyClassPtr> * operator ->() const {return this;}
const MyClassOp<MyClassPtr> & operator *() const {return *this;}
...
}
class MyClassPtr : private MyClassOp<MyClassPtr>
{
public:
MyClassOp<MyClassPtr> * operator ->() {return this;}
MyClassOp<MyClassPtr> & operator *() {return *this;}
...
}
This works O.K., but is a bit cumbersome. If I have for example equality operator I need to write something like *myptr1 == myptr2 to compare values kept by two MyClassPtr objects (it's easy to make a mistake and compare myptr1 == myptr2 or expect that something like *myptr1 == *myptr2 could work). Also when I have allocating type:
class MyClass : public MyClassOp<MyClass>
{
MyClass(int x, int y, int z);
...
int m_arr[3];
}
I would want to be able to use temporaries as function arguments.
void f(const_MyClassPtr my);
//use temporary when calling f()
f(MyClass(1, 2, 3));
I can do this by providing conversion operators or conversion constructors (that convert MyClass to const_MyClassPtr). But then const_MyClassPtr behaves more like reference than pointer. If iterators are generalization of pointers then why one could not imitate reference? Therefore I divided MyClassOp into two parts (const and non const) and replaced -> and * operators implemented by const_MyClassPtr and MyClassPtr with public inheritance and changed their names to ressemble reference. I ended up with following structures.
MyClassOp : public const_MyClassOp
const_MyClassRef : public const_MyClassOp<const_MyClassRef>
MyClassRef : public MyClassOp<MyClassRef>
MyClass : public MyClassOp<MyClass>
However const_MyClassRef and MyClassRef are not perfect generalization of reference as it impossible to imitate some of C++ reference properties, so Ref suffix is there to denote reference-like structure.
Maybe you can find some hints in effective c++ item 4 "Avoid duplication in const and non-const Member function"
I may summarize like following ( it makes you avoid code duplication even if using somewhat ugly cast ):
struct my_class
{
my_class(int x):_x(x){};
const int& method(void) const;
int& method(void);
int _x;
};
const int& my_class::method(void) const //func for const instance
{
return _x;
}
int& my_class::method(void) //func for normal instance
{
return const_cast<int& >(static_cast<const my_class& >(*this).method()) ;
}
int main()
{
my_class a(1);
const my_class b(2);
a.method() = 5;
cout << a.method() << endl;
//b.method() = 4; //b is const, wont compile
cout << b.method() << endl;
return 0;
}
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.
I have the following (very simplified) "container" class:
class container
{
public:
template<typename T> container(const boost::shared_ptr<T> &rhs)
: m_content(rhs) { }
template<typename T>
operator T const & () const
{
return get<T>();
}
template<typename T>
T const & get() const
{
return *boost::any_cast< boost::shared_ptr<T> >(m_content);
}
private:
boost::any m_content;
};
It should store objects in the boost::any container in the form of a shared pointer. If I store some object, say, of the boost::shared_ptr<some_type> type in the container, I would like to get the reference (const some_type&) simply by a user-defined conversion which would allow to do something like this:
boost::shared_ptr<some_type> x(new some_type);
container cx = x;
...
// user-defined conversion
const some_type &y = cx;
// a template conversion using a "getter"
const some_type &y = cx.get<some_type>();
Sometimes, I need to store objects derived from some abstract type and do the same sort of type conversion to the reference of this abstract type, for example, like this:
boost::shared_ptr<some_abstract_type> x(new some_derived_type);
container cx = x;
...
// user-defined conversion
const some_abstract_type &y = cx;
// a template conversion using a "getter"
const some_abstract_type &y = cx.get<some_abstract_type>();
Both the user-defined conversion and the template "getter" work fine with GCC. However, the Intel C++ compiler seems to have a problem with the (user-defined) conversion while the "getter" works.
For example, the following code works with GCC but not with Intel:
#include <iostream>
#include <boost/any.hpp>
#include <boost/shared_ptr.hpp>
class container
{
public:
template<typename T> container(const boost::shared_ptr<T> &rhs)
: m_content(rhs) { }
template<typename T>
operator T const & () const
{
return get<T>();
}
template<typename T>
T const & get() const
{
return *boost::any_cast< boost::shared_ptr<T> >(m_content);
}
private:
boost::any m_content;
};
class base
{
public:
virtual ~base() { }
virtual void f() const = 0;
};
class derived : public base
{
public:
virtual ~derived() { }
virtual void f() const { std::cout << "hello\n"; }
};
void foo(const container &c)
{
const base & a = c;
a.f();
}
int main()
{
boost::shared_ptr<base> a(new derived);
container c = a;
foo(c);
}
With Intel, I get this error:
test.cpp(44): error: no suitable user-defined conversion from "const container" to "const base" exists
const base & a = c;
^
compilation aborted for test.cpp (code 2)
On the other hand, if I replace base with derived in both main() and foo() (or use the "getter" instead of the type conversion in foo()), everything works fine with Intel too. Is it possible to convince the Intel compiler to use the user-defined type conversion to the reference type when T is an abstract class?
Thanks in advance for any ideas.
EDIT: Interestingly, using the type conversion to the pointer type works fine. If I add
template<typename T>
operator T const * () const
{
return &get<T>();
}
to the container class and replace foo() with
void foo(const container &c)
{
const base * a = c;
a->f();
}
then it works also with Intel.
I would return a pointer in the getter:
template<typename T>
T const * get() const {
return boost::any_cast< boost::shared_ptr<T> >(m_content);
}
This avoids the conversion problem, and does not crash immediately if you pass a null pointer to your container.
Example:
void foo(const container &c)
{
const base* a = c.get<base>();
a->f();
}
You could also add a function valid() which checks if there is something in the container:
bool valid() const {
return m_content != NULL;
}
Edit: Your addition to your question follows exactly in this direction.
Ok, so it seems that it is a bug in the Intel C++ compiler and was filed in the bug tracking list.
I am having trouble with the initialization of this struct (simplified for example)
struct S{ const float * const * const data;};
Basically I have a buffer of buffers of floats, and I use const to ensure someone using S cannot change anything to this member (read only).
My problem is that this is complicated and hard to read to initialize, I would like to use a lambda that return an const S, and so I could initialize members in my lambda by writing the member name : s.data = ptr;
Now this code is complex and I wonder what could be a better solution.
AFAIK, having struct S{float ** data;} a const S would not protect as efficiently the content of the member, I could not modify S::data, but I could modify *S::data.
How should I do ?
Thank you
Why not just remove the last const?
struct S{ const float * const * data;};
That way you can initialize data however you like, and it still can't be used to modify anything it points to.
data itself can be modified, but should that be prevented, it should simply be private.
The recommended way is to add a constructor to S. This allows you to set the value of data in the ctor initializer list.
struct S
{
explicit S(const float *const *const d) : data(d) {}
const float * const * const data;
};
S GetS()
{
float **data = GetData();
return S(data);
}
If you want to restrict who can change S::data after it has been initialized you can box the member variable and use friendship to allow access. This requires encapsulating the data member in an additional struct that provides conversion and assignment operators.
struct Outer
{
struct S
{
private:
struct ConstBox
{
friend Outer;
ConstBox(const ConstBox& other) : data_(other.data_) {}
explicit ConstBox(const float *const *const data) : data_(data) {}
operator const float* const* () const { return data_; }
private:
ConstBox& operator=(const float * const * data)
{
data_ = data;
return *this;
}
const float * const * data_;
};
public:
S() : data(nullptr) {}
explicit S(const float *const *const d) : data(d) {}
ConstBox data;
};
S DoSomething() const
{
S s(nullptr);
auto f = []() -> S
{
S s;
s.data = new float*[10];
return s;
};
return f();
}
};
typedef Outer::S S;
void FailTest()
{
S s;
s.data = nullptr; // <-- fails
float** v1 = s.data; // <-- fails
const float** v1 = s.data; // <-- fails
// These are ok
const float* const* v2 = s.data;
}
#CaptainObvious's answer is the correct one. Write a constructor for S, taking whatever arguments it needs, and use a member initialiser rather than an assignment statement to set 'data'.
With your simplified example I would simply do:
struct S{ float const * const * const data;};
auto create_buffer() -> float const * const * {
float **buf;
/* ... compute buffer contents */
return buf;
}
S s {create_buffer()};
However, in a comment you mention that you have many members and that initializing members based on order is not sufficiently clear.
struct S { const A a; const B b; const C c; };
S s {x,y,z}; // order based, not readable enough.
const members must be initialized as part of the object's construction. You must either specify them somehow in the initializer, or you must set their value in the class, so that they are set at construction time.
Solution 1
One way to pass them during construction, but in a readable fashion is to use a second object to help initialization:
struct S_initializer { A a; B b; C c; }
struct S {
const A a; const B b; const C c;
S(S_initializer &s) : a(s.a), b(s.b), c(s.c) {}
};
S make_S() {
S_initializer s;
s.a = x;
s.b = y;
s.c = z;
return S{s};
}
The above involves some repitition, which you can avoid by just making the initialization helper object a const member of S:
struct S {
const S_initializer m;
S(S_initializer &s) : m{s} {}
};
S make_S() {
S_initializer s;
s.a = x;
s.b = y;
s.c = z;
return S{s};
}
The tradeoff is that now to access the members of S you have to have an extra .m in there:
A a = s.m.a; // versus just s.a;
Solution 2
A second method relies on a compiler extension; Although not standard C++, gcc and clang implement C99 designated initializers in C++. VC++ does not implement this.
S s { .a = x, .b = y, .c = z };