Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Compiler Error in Template Functions...? [modified]

Compiler Error in Template Functions...? [modified]

Scheduled Pinned Locked Moved C / C++ / MFC
helpc++comquestion
9 Posts 4 Posters 2 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    Joseph Dempsey
    wrote on last edited by
    #1

    I have run into a very strange error today and was wondering if anyone else has seen this. Some digging on google suggests it might be a compiler error. I've seen this on VS2008 and GCC 4.1.2. I was able to build a test harness to repro the issue. It is below:

    #include class Cloneable
    {
    public:
    template TYPE* clone() const { return dynamic_cast< TYPE* > ( clone() ); }
    virtual Cloneable* clone() const = 0;
    };

    // simple template class that defines an interface
    // for cloning objects.
    class X : public Cloneable
    {
    public:
    X(int _y ) : data(_y) { }
    virtual ~X() { /* DO NOTHING */ }
    virtual Cloneable* clone() const { return new X(data); }

    protected:
    X() { /* DO NOTHING */ }
    int data;
    };

    class Y : public X
    {
    public:
    Y(double f, int y) : X(y), dataf(f) { /* DO NOTHING */ }
    virtual ~Y() { /* DO NOTHING */ }

    virtual Cloneable\* clone() const { return new Y(dataf, data); }
    

    protected:
    double dataf;
    };

    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    int main(int argc, char* argv[])
    {
    X* x = new X(1);
    X* x1 = x->clone();

    Y\* y = new Y(2.12, 4);
    Y\* y1 = y->clone();
    
    delete y;
    delete y1;
    delete x;
    delete x1;
    
    return 0;
    

    }

    The clone fails in both cases in the main function. It should cast properly. There seem to be two ways to fix this. If i move the templated function from Cloneable to X & Y it works in both cases. The other is to use clone() in the main function and dyna cast there. A standard C cast in the templated function also doesn't work. Its like the compiler is erroneously changing the protection level on the function and then gets confused and just dumps out the error.

    1>Compiling...
    1>main.cpp
    1>.\main.cpp(40) : error C2275: 'X' : illegal use of this type as an expression
    1> .\main.cpp(12) : see declaration of 'X'
    1>.\main.cpp(40) : error C2059: syntax error : ')'
    1>.\main.cpp(43) : error C2275: 'Y' : illegal use of this type as an expression
    1> .\main.cpp(24) : see declaration of 'Y'
    1>.\main.cpp(43) : error C2059: syntax error : ')'

    Anyone seen this work in a different compiler or know of a workaround to make it compile (aside from the ones I mentioned)? -- Joseph Dempsey Sr. Software Engineer joseph_r_dempsey@yahoo.com

    modified on Friday, November 5, 2010 2:18 PM

    _ A P 3 Replies Last reply
    0
    • J Joseph Dempsey

      I have run into a very strange error today and was wondering if anyone else has seen this. Some digging on google suggests it might be a compiler error. I've seen this on VS2008 and GCC 4.1.2. I was able to build a test harness to repro the issue. It is below:

      #include class Cloneable
      {
      public:
      template TYPE* clone() const { return dynamic_cast< TYPE* > ( clone() ); }
      virtual Cloneable* clone() const = 0;
      };

      // simple template class that defines an interface
      // for cloning objects.
      class X : public Cloneable
      {
      public:
      X(int _y ) : data(_y) { }
      virtual ~X() { /* DO NOTHING */ }
      virtual Cloneable* clone() const { return new X(data); }

      protected:
      X() { /* DO NOTHING */ }
      int data;
      };

      class Y : public X
      {
      public:
      Y(double f, int y) : X(y), dataf(f) { /* DO NOTHING */ }
      virtual ~Y() { /* DO NOTHING */ }

      virtual Cloneable\* clone() const { return new Y(dataf, data); }
      

      protected:
      double dataf;
      };

      // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

      int main(int argc, char* argv[])
      {
      X* x = new X(1);
      X* x1 = x->clone();

      Y\* y = new Y(2.12, 4);
      Y\* y1 = y->clone();
      
      delete y;
      delete y1;
      delete x;
      delete x1;
      
      return 0;
      

      }

      The clone fails in both cases in the main function. It should cast properly. There seem to be two ways to fix this. If i move the templated function from Cloneable to X & Y it works in both cases. The other is to use clone() in the main function and dyna cast there. A standard C cast in the templated function also doesn't work. Its like the compiler is erroneously changing the protection level on the function and then gets confused and just dumps out the error.

      1>Compiling...
      1>main.cpp
      1>.\main.cpp(40) : error C2275: 'X' : illegal use of this type as an expression
      1> .\main.cpp(12) : see declaration of 'X'
      1>.\main.cpp(40) : error C2059: syntax error : ')'
      1>.\main.cpp(43) : error C2275: 'Y' : illegal use of this type as an expression
      1> .\main.cpp(24) : see declaration of 'Y'
      1>.\main.cpp(43) : error C2059: syntax error : ')'

      Anyone seen this work in a different compiler or know of a workaround to make it compile (aside from the ones I mentioned)? -- Joseph Dempsey Sr. Software Engineer joseph_r_dempsey@yahoo.com

      modified on Friday, November 5, 2010 2:18 PM

      _ Offline
      _ Offline
      _Superman_
      wrote on last edited by
      #2

      You're code is not fully visible. Make sure "Encode < characters while pasting" option is checked while you paste your code.

      «_Superman_» _I love work. It gives me something to do between weekends.

      _Microsoft MVP (Visual C++)

      Polymorphism in C

      J 1 Reply Last reply
      0
      • _ _Superman_

        You're code is not fully visible. Make sure "Encode < characters while pasting" option is checked while you paste your code.

        «_Superman_» _I love work. It gives me something to do between weekends.

        _Microsoft MVP (Visual C++)

        Polymorphism in C

        J Offline
        J Offline
        Joseph Dempsey
        wrote on last edited by
        #3

        It was already checked. It shows up fully in my browser (chrome) and in IE just fine. Not sure why you can't see it.

        -- Joseph Dempsey Sr. Software Engineer joseph_r_dempsey@yahoo.com

        _ 1 Reply Last reply
        0
        • J Joseph Dempsey

          It was already checked. It shows up fully in my browser (chrome) and in IE just fine. Not sure why you can't see it.

          -- Joseph Dempsey Sr. Software Engineer joseph_r_dempsey@yahoo.com

          _ Offline
          _ Offline
          _Superman_
          wrote on last edited by
          #4

          I'm using chrome and this is what I see -

          #include

          class Cloneable
          {
          public:
          template TYPE* clone() const { return dynamic_cast< TYPE* > ( clone() ); }
          virtual Cloneable* clone() const = 0;
          };

          // simple template class that defines an interface
          // for cloning objects.
          class X : public Cloneable
          {
          public:
          X(int _y ) : data(_y) { }
          virtual ~X() { /* DO NOTHING */ }
          virtual Cloneable* clone() const { return new X(data); }

          protected:
          X() { /* DO NOTHING */ }
          int data;
          };

          class Y : public X
          {
          public:
          Y(double f, int y) : X(y), dataf(f) { /* DO NOTHING */ }
          virtual ~Y() { /* DO NOTHING */ }

          virtual Cloneable\* clone() const { return new Y(dataf, data); }
          

          protected:
          double dataf;
          };

          // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

          int main(int argc, char* argv[])
          {
          X* x = new X(1);
          X* x1 = x->clone();

          Y\* y = new Y(2.12, 4);
          Y\* y1 = y->clone();
          
          delete y;
          delete y1;
          delete x;
          delete x1;
          
          return 0;
          

          }

          «_Superman_» _I love work. It gives me something to do between weekends.

          _Microsoft MVP (Visual C++)

          Polymorphism in C

          J 1 Reply Last reply
          0
          • _ _Superman_

            I'm using chrome and this is what I see -

            #include

            class Cloneable
            {
            public:
            template TYPE* clone() const { return dynamic_cast< TYPE* > ( clone() ); }
            virtual Cloneable* clone() const = 0;
            };

            // simple template class that defines an interface
            // for cloning objects.
            class X : public Cloneable
            {
            public:
            X(int _y ) : data(_y) { }
            virtual ~X() { /* DO NOTHING */ }
            virtual Cloneable* clone() const { return new X(data); }

            protected:
            X() { /* DO NOTHING */ }
            int data;
            };

            class Y : public X
            {
            public:
            Y(double f, int y) : X(y), dataf(f) { /* DO NOTHING */ }
            virtual ~Y() { /* DO NOTHING */ }

            virtual Cloneable\* clone() const { return new Y(dataf, data); }
            

            protected:
            double dataf;
            };

            // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            int main(int argc, char* argv[])
            {
            X* x = new X(1);
            X* x1 = x->clone();

            Y\* y = new Y(2.12, 4);
            Y\* y1 = y->clone();
            
            delete y;
            delete y1;
            delete x;
            delete x1;
            
            return 0;
            

            }

            «_Superman_» _I love work. It gives me something to do between weekends.

            _Microsoft MVP (Visual C++)

            Polymorphism in C

            J Offline
            J Offline
            Joseph Dempsey
            wrote on last edited by
            #5

            ok... not sure whats going on there but i tried repasting it with and w/o the checkbox and it still shows up erred. Its missing the angle brackets obviously. The code itself is correct syntactically. Just pretend they are there :) If you're real interested in seeing the actual file i can email it. * EDIT: Screw it... just removed HTML completely. should show up right now.

            -- Joseph Dempsey Sr. Software Engineer joseph_r_dempsey@yahoo.com

            _ 1 Reply Last reply
            0
            • J Joseph Dempsey

              ok... not sure whats going on there but i tried repasting it with and w/o the checkbox and it still shows up erred. Its missing the angle brackets obviously. The code itself is correct syntactically. Just pretend they are there :) If you're real interested in seeing the actual file i can email it. * EDIT: Screw it... just removed HTML completely. should show up right now.

              -- Joseph Dempsey Sr. Software Engineer joseph_r_dempsey@yahoo.com

              _ Offline
              _ Offline
              _Superman_
              wrote on last edited by
              #6

              You're trying to overload across class boundaries. Take a look at this FAQ - http://www.research.att.com/~bs/bs_faq2.html#overloadderived[^] So you will need the add the following line in your derived classes - using Cloneable::clone;

              «_Superman_»

              _I love work. It gives me something to do between weekends.

              _Microsoft MVP (Visual C++)

              Polymorphism in C

              A 1 Reply Last reply
              0
              • J Joseph Dempsey

                I have run into a very strange error today and was wondering if anyone else has seen this. Some digging on google suggests it might be a compiler error. I've seen this on VS2008 and GCC 4.1.2. I was able to build a test harness to repro the issue. It is below:

                #include class Cloneable
                {
                public:
                template TYPE* clone() const { return dynamic_cast< TYPE* > ( clone() ); }
                virtual Cloneable* clone() const = 0;
                };

                // simple template class that defines an interface
                // for cloning objects.
                class X : public Cloneable
                {
                public:
                X(int _y ) : data(_y) { }
                virtual ~X() { /* DO NOTHING */ }
                virtual Cloneable* clone() const { return new X(data); }

                protected:
                X() { /* DO NOTHING */ }
                int data;
                };

                class Y : public X
                {
                public:
                Y(double f, int y) : X(y), dataf(f) { /* DO NOTHING */ }
                virtual ~Y() { /* DO NOTHING */ }

                virtual Cloneable\* clone() const { return new Y(dataf, data); }
                

                protected:
                double dataf;
                };

                // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                int main(int argc, char* argv[])
                {
                X* x = new X(1);
                X* x1 = x->clone();

                Y\* y = new Y(2.12, 4);
                Y\* y1 = y->clone();
                
                delete y;
                delete y1;
                delete x;
                delete x1;
                
                return 0;
                

                }

                The clone fails in both cases in the main function. It should cast properly. There seem to be two ways to fix this. If i move the templated function from Cloneable to X & Y it works in both cases. The other is to use clone() in the main function and dyna cast there. A standard C cast in the templated function also doesn't work. Its like the compiler is erroneously changing the protection level on the function and then gets confused and just dumps out the error.

                1>Compiling...
                1>main.cpp
                1>.\main.cpp(40) : error C2275: 'X' : illegal use of this type as an expression
                1> .\main.cpp(12) : see declaration of 'X'
                1>.\main.cpp(40) : error C2059: syntax error : ')'
                1>.\main.cpp(43) : error C2275: 'Y' : illegal use of this type as an expression
                1> .\main.cpp(24) : see declaration of 'Y'
                1>.\main.cpp(43) : error C2059: syntax error : ')'

                Anyone seen this work in a different compiler or know of a workaround to make it compile (aside from the ones I mentioned)? -- Joseph Dempsey Sr. Software Engineer joseph_r_dempsey@yahoo.com

                modified on Friday, November 5, 2010 2:18 PM

                A Offline
                A Offline
                Aescleal
                wrote on last edited by
                #7

                Have a dig in the standard for the rules on overload resolution and how it interacts with template expansion. As both VC++ later than 2002 and gcc 4.x agree on the behaviour it's probably standard. Essentially it looks like what's happening is that clone<T> is not part of the overload set for Y::clone() and X::clone() as there functions with that name already in the class of the pointer you're calling through. One of three solutions spring to mind. Either make clone an ordinary function, change it's name or call it explicitly. e.g. if you change your base class to:

                class Cloneable
                {
                public:
                template<class TYPE> TYPE* clone_as() const { return dynamic_cast< TYPE* > ( clone() ); }
                virtual Cloneable* clone() const = 0;
                };

                and change your client code to match things work the way I think you think they should. Incidentally be very careful writing code like this... You can write leaky code very easily:

                int main()
                {
                X x( 7 );
                Cloneable *p = &x;

                Y \*py = p->clone\_as<Y>();
                

                }

                leaks an X. I'd be tempted to return shared_ptrs or auto_ptrs to avoid this sort of faux pas. Basically the interaction between overloading, overriding and templates (i.e. when templates are expanded and considered part of the set of overload candidates) is a nightmare. My advice would be avoid it unless you're writing a compiler. Cheers, Ash PS: This is very similar to the well known interaction between overrides and overloads with implicit conversion:

                class base
                {
                public:
                virtual void do_something( int ) { std::cout << "Doing the base class int thing" << std::endl; }
                virtual void do_something( double ) { std::cout << "Doing the base class double thing" << std::endl; }
                };

                class derived : public base
                {
                public:
                virtual void do_something( double ) { std::cout << "Doing the derived class double thing" << std::endl; }
                };

                int main()
                {
                derived d;
                d.do_something( int( 7 ) );
                }

                This could always prints the derived class double message. You get around this by either changing the name or calling the function explicitly. PPS: Superman's solution from the mouth of Bjarne would work as well - I didn't consider it as using declarations have their own fun properties which you may or may not be happy with.

                modified on Saturday, November 6, 2010 2:48 AM

                1 Reply Last reply
                0
                • _ _Superman_

                  You're trying to overload across class boundaries. Take a look at this FAQ - http://www.research.att.com/~bs/bs_faq2.html#overloadderived[^] So you will need the add the following line in your derived classes - using Cloneable::clone;

                  «_Superman_»

                  _I love work. It gives me something to do between weekends.

                  _Microsoft MVP (Visual C++)

                  Polymorphism in C

                  A Offline
                  A Offline
                  Aescleal
                  wrote on last edited by
                  #8

                  Good call, forgot about using using to add functions to the overload set. Cheers, Ash

                  1 Reply Last reply
                  0
                  • J Joseph Dempsey

                    I have run into a very strange error today and was wondering if anyone else has seen this. Some digging on google suggests it might be a compiler error. I've seen this on VS2008 and GCC 4.1.2. I was able to build a test harness to repro the issue. It is below:

                    #include class Cloneable
                    {
                    public:
                    template TYPE* clone() const { return dynamic_cast< TYPE* > ( clone() ); }
                    virtual Cloneable* clone() const = 0;
                    };

                    // simple template class that defines an interface
                    // for cloning objects.
                    class X : public Cloneable
                    {
                    public:
                    X(int _y ) : data(_y) { }
                    virtual ~X() { /* DO NOTHING */ }
                    virtual Cloneable* clone() const { return new X(data); }

                    protected:
                    X() { /* DO NOTHING */ }
                    int data;
                    };

                    class Y : public X
                    {
                    public:
                    Y(double f, int y) : X(y), dataf(f) { /* DO NOTHING */ }
                    virtual ~Y() { /* DO NOTHING */ }

                    virtual Cloneable\* clone() const { return new Y(dataf, data); }
                    

                    protected:
                    double dataf;
                    };

                    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                    int main(int argc, char* argv[])
                    {
                    X* x = new X(1);
                    X* x1 = x->clone();

                    Y\* y = new Y(2.12, 4);
                    Y\* y1 = y->clone();
                    
                    delete y;
                    delete y1;
                    delete x;
                    delete x1;
                    
                    return 0;
                    

                    }

                    The clone fails in both cases in the main function. It should cast properly. There seem to be two ways to fix this. If i move the templated function from Cloneable to X & Y it works in both cases. The other is to use clone() in the main function and dyna cast there. A standard C cast in the templated function also doesn't work. Its like the compiler is erroneously changing the protection level on the function and then gets confused and just dumps out the error.

                    1>Compiling...
                    1>main.cpp
                    1>.\main.cpp(40) : error C2275: 'X' : illegal use of this type as an expression
                    1> .\main.cpp(12) : see declaration of 'X'
                    1>.\main.cpp(40) : error C2059: syntax error : ')'
                    1>.\main.cpp(43) : error C2275: 'Y' : illegal use of this type as an expression
                    1> .\main.cpp(24) : see declaration of 'Y'
                    1>.\main.cpp(43) : error C2059: syntax error : ')'

                    Anyone seen this work in a different compiler or know of a workaround to make it compile (aside from the ones I mentioned)? -- Joseph Dempsey Sr. Software Engineer joseph_r_dempsey@yahoo.com

                    modified on Friday, November 5, 2010 2:18 PM

                    P Offline
                    P Offline
                    Paul Michalik
                    wrote on last edited by
                    #9

                    I wouldn't recommend to do it that way at all.. Let Clonable be what it is, an interface with no implementation, skip the template member completely. In your example you don't need to cast anything, if you use covariant return type for overrides of clone inimplementations of Clonable:

                    class X : public Cloneable
                    {
                    virtual X* clone() const { return new X(data); }
                    };

                    class Y : public X
                    {
                    virtual Y* clone() const { return new Y(dataf, data); }
                    };

                    int main(int argc, char* argv[])
                    {
                    X* x = new X(1);
                    X* x1 = x->clone();

                      Y\* y = new Y(2.12, 4);
                      Y\* y1 = y->clone();
                    
                      return 0;
                    

                    }

                    As suggested above, usage of an std::auto_ptr is preferable, but only in client code, since otherwise you loose the ability to define covariant return types. I am using a "Cloner" utility for comfortable casts to derived types which looks something like this:

                    class ClonerUtility {

                    template <class TCoVariantClonable>
                    static std::auto_ptr<TCoVariantClonable> CloneAs(const Clonable& pToBeCloned) {
                    std::auto_ptr<Clonable> tClone(pToBeCloned.clone());
                    if (TCoVariantClonable* tCoVariantClone =
                    dynamic_cast<TCoVariantClonable*>(tClone.get())) {
                    tClone.reset(0);
                    return std::auto_ptr<TCoVariantClonable>(tCoVariantClone);
                    }
                    return std::auto_ptr<TCoVariantClonable>();
                    }

                    template<class TCoVariantClonable>
                    static std::auto_ptr<TCoVariantClonable> Clone(const TCoVariantClonable& pToBeCloned) {
                    return std::auto_ptr<TCoVariantClonable>(pToBeCloned.clone());
                    }
                    };

                    //
                    int main(int argc, char* argv[])
                    {
                    std::auto_ptr<X> tX(new X);
                    std::auto_ptr<X> tCloneX = ClonerUtility::Clone(*tX);

                    Clonable& tPureClonable = *tCloneX;
                    std::auto_ptr<X> tOtherCloneOfX = ClonerUtility::CloneAs<X>(tPureClonable);
                    }

                    modified on Sunday, November 7, 2010 4:05 AM

                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • World
                    • Users
                    • Groups