Templated user-defined type conversion to abstract reference type

Templated user-defined type conversion to abstract reference type

I have the following (very simplified) "container" class to store objects of "any" type in shared pointers:

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;
};

If I store an object of some type in the container, I would like to get the reference simply by a user-defined conversion which would allow to do something like this:

boost::shared_ptr<some_type> x(new some_type);
container c_x = x;
    
// Two methods of getting the reference to the instance stored
// in c_x are possible:

// 1) using a user-defined conversion:
const some_type &y = c_x;

// 2) using a const-reference using a "getter":
const some_type &y = c_x.get<some_type>();

Of course, the first approach is preferred by me as it is much simpler. 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 c_x = x;

// Obtain the reference to the abstract type:    

// 1) using a user-defined conversion:
const some_abstract_type &y = c_x;

// 2) using a const-reference using a "getter":
const some_abstract_type &y = c_x.get<some_abstract_type>();

Now the problem arises with the Intel compiler (I use the version 13.1). Both approaches (1) and (2) work fine with GCC. However, the Intel compiler seems to have a problem with using the defined type conversion when the template type is abstract.

For example, the following code works fine with GCC but fails 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 reference "getter" instead of the type conversion in "foo()"), everything works fine with Intel too. Is it possible to convince the compiler to use the user-defined type conversion to the reference type when T is an abstract class? Am I doing something wrong or is this a missing feature (a bug?) in the Intel C++ compiler?

Interestingly, the conversion to the const pointer is not a problem. 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 the code works also with Intel.

Thanks in advance for any feedback.

 

2 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

 

Hi,

This looks like an Intel compiler bug to me (both Microsoft and GNU accept the small example below but Intel does not):

struct container
{
   template<typename T> operator T const & () const;
};

struct base
{
#ifdef OK
   virtual void f();
#else
   virtual void f() = 0; // causes conversion error
#endif
};

void foo(const container &c)
{
  const base& a = c;
}

int main()
{
  container c;
  foo(c);
  return 0;
}

I have entered this in our bug tracking system as DPD200254930. Thanks for reporting it to us. A possible workaround is making the pure virtual function base:;f() a non pure virtual function.

Judy

 

Leave a Comment

Please sign in to add a comment. Not a member? Join today