Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.
7956 Discussions

Templated user-defined type conversion to abstract reference type

Pavel_J_
Beginner
565 Views

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.

 

0 Kudos
1 Reply
Judith_W_Intel
Employee
565 Views

 

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

 

0 Kudos
Reply