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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With