CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 14 of 14
  1. #1
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588

    Templates increase code size, a way around this ?

    I like templates and even if I didn't I would still have to use them since ATL is mostly based on them.

    But the problem I face (I think, please correct me if I'm wrong) is that whenever a template class is instantiated with a different parameter, all of its functions are "written out in full" by the compiler. This is usually fine, but the problem comes from the functions in the class which don't depend on the template parameters. They should not need to get get duplicated and unneccessarily increase the code size.

    My concrete problem is that I have defined a templated "boiler-plate" windowed ActiveX object derived from about 15 ATL templates and a few of my own classes that does the basic window management, forwards the messages appropriately and does some other funky stuff.

    The only reason I have to make this class templated is that otherwise I can't derive it from the basic ATL templates, don't have access to the required ATL variables (like m_bWindowOnly e.g.), can't call base functions (in only a very few of my functions) and can't expect ATL to call my overridden virtual functions.

    Most of the overridden virtual functions don't require any template arguments, so having them in the templated class unfortunately duplicates them in the compiler-generated code and increases the size :/

    What could I do ?
    Get this small utility to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
    Supports C++ and VB out of the box, but can be configured for other languages.

  2. #2
    Join Date
    Mar 2002
    Location
    California
    Posts
    1,582
    This is usually fine, but the problem comes from the functions in the class which don't depend on the template parameters.
    These don't need to be inlined. Put them in an implementation file.

    Jeff

  3. #3
    Join Date
    Jun 2001
    Location
    Switzerland
    Posts
    4,443

    Re: Templates increase code size, a way around this ?

    Originally posted by Yves M
    But the problem I face (I think, please correct me if I'm wrong) is that whenever a template class is instantiated with a different parameter, all of its functions are "written out in full" by the compiler.
    AFAIK, only functions that are actually used get instantiated.
    Gabriel, CodeGuru moderator

    Forever trusting who we are
    And nothing else matters
    - Metallica

    Learn about the advantages of std::vector.

  4. #4
    Join Date
    Aug 2000
    Location
    New Jersey
    Posts
    968
    What you can do is put the code that doesn't need the template parameters, in a parrent class, and have your template parameter class inherit this parent class. That way the parent class can have the function implementation inside a *.cpp file, and the functions that need the template parameters can be put in the template class.

    Example:

    class foo
    {
    public:
    void SomeFunctionThatDoesntNeedTemplatePar();
    };

    template<class T>
    class TemplateClass : public foo
    {
    public:
    T FunctionThatNeedsTemplate(){
    return T();
    }
    };

    //*.cpp
    void SomeFunctionThatDoesntNeedTemplatePar()
    {
    //Code
    }
    David Maisonave
    Author of Policy Based Synchronized Smart Pointer
    http://axter.com/smartptr


    Top ten member of C++ Expert Exchange.
    C++ Topic Area

  5. #5
    Join Date
    Mar 2002
    Location
    California
    Posts
    1,582
    You don't need a parent class. Simply put the methods that don't use the template parameter in the .cpp file.

    Jeff

  6. #6
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588

    Re: Re: Templates increase code size, a way around this ?

    Thanks for the help

    AFAIK, only functions that are actually used get instantiated.
    Sure, but all the functions do get used They are mostly overrides for the standard handling that ATL does, so they will get called.

    Axter and Jeff:
    Unfortunately most of the functions do depend on stuff provided by the base ATL classes. To use a simple description, here is what it looks like:
    Code:
    // An ATL class that provides the basic functionality
    // I derive from about 15 of these
    template <class Base>
    class ATLBaseComObject
    {
    public:
      HWND GetHwnd() {/*code*/}
      HRESULT IOleObject_SetClientSite() {/*code*/}
      // ...
    };
    
    // My "boiler-plate" implementation
    // (has actually 5 template parameters)
    template <class Base>
    class BoilerPlate : public ATLBaseComObject<Base>
    {
    public:
      // STDMETHOD stands for "virtual HRESULT __stdcall"
      // This method does not need the template parameters
      // But does need the base class functionality
      STDMETHOD(Refresh)()
      {
        HWND hwnd = GetHwnd();
        ::RedrawWindow(hwnd, 0, 0, RDW_UPDATENOW);
        return S_OK;
      }
    
      // This method needs the template parameter
      STDMETHOD(IOleObject_SetClientSite)()
      {
        HRESULT hr = ATLBaseComObject<Base>::IOleObject_SetClientSite();
        Refresh();
        return hr;
      }
    };
    
    class CFinal : public BoilerPlate<CFinal>
    {
    public:
      STDMETHOD(SomeStuff)()
      {
         // Update the data and refresh the view
         RefreshView();
      }
    };
    Simply put the methods that don't use the template parameter in the .cpp file.
    This I don't understand :/ Do you mean to write it in Final.cpp ?That would defeat the point of the Boilerplate class :/
    Get this small utility to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
    Supports C++ and VB out of the box, but can be configured for other languages.

  7. #7
    Join Date
    Mar 2002
    Location
    California
    Posts
    1,582
    I mean write a BoilerPlate.cpp, and methods like the following, which don't rely on the template parameter Base can be implemented in BoilerPlate.cpp.

    Code:
      STDMETHOD(Refresh)()
      {
        HWND hwnd = GetHwnd();
        ::RedrawWindow(hwnd, 0, 0, RDW_UPDATENOW);
        return S_OK;
      }
    Then again, I don't use ATL, and there may be more going on here than I realize. However, the only reason you need to inline template class methods is that each different template parameter creates a different version of that method. If the template parameter is not used, that method does not need to be inlined.

    Jeff

  8. #8
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588
    The problem is just that GetHwnd() is in this case a call to ATLBaseComObject<Base>::GetHwnd(), but the qualfier is not needed since I don't care which one of the base classes implements this as long as one of them does it. If I would write this method in a non-templated class then only one copy of this function would need to be present in the final executable, not one of every template parameter :/

    However, the only reason you need to inline template class methods is that each different template parameter creates a different version of that method. If the template parameter is not used, that method does not need to be inlined.
    Do you mean that writing something along these lines would work ? I don't think it does :/
    Code:
    // BoilerPlate.h
    template <class Base>
    class BoilerPlate : public ATLBaseComObject<Base>
    {
    public:
      // STDMETHOD stands for "virtual HRESULT __stdcall"
      // This method does not need the template parameters
      // But does need the base class functionality
      STDMETHOD(Refresh)();
    
      // This method needs the template parameter
      STDMETHOD(IOleObject_SetClientSite)()
      {
        HRESULT hr = ATLBaseComObject<Base>::IOleObject_SetClientSite();
        Refresh();
        return hr;
      }
    };
    
    // BoilerPlate.cpp
    STDMETHOD(Refresh)();
    {
      HWND hwnd = GetHwnd();
      ::RedrawWindow(hwnd, 0, 0, RDW_UPDATENOW);
      return S_OK;
    }
    Get this small utility to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
    Supports C++ and VB out of the box, but can be configured for other languages.

  9. #9
    Join Date
    Mar 2002
    Location
    California
    Posts
    1,582
    well, STDMETHOD won't work. You need className::, and you also don't want 'virtual'.

    Jeff

  10. #10
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588
    Sure, but how ?
    Code:
    HRESULT BoilerPlate::Refresh()
    {
      HWND hwnd = GetHwnd();
      ::RedrawWindow(hwnd, 0, 0, RDW_UPDATENOW);
      return S_OK;
    }
    Of course this won't work either, but I don't see what you are getting at.
    Get this small utility to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
    Supports C++ and VB out of the box, but can be configured for other languages.

  11. #11
    Join Date
    Mar 2002
    Location
    California
    Posts
    1,582
    I'm completely wrong. Sorry about that. I thought you could do:

    Code:
    template<typename T>
    HRESULT BoilerPlate<T>::Refresh()
    {
         // never uses T...
    }
    in the implementation file, but you can't. What I got mixed up with is that you can do this with specific types, such as

    Code:
    HRESULT BoilerPlate<double>::Refresh()
    {
       // ...
    }

    Jeff

  12. #12
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588
    Oh ok

    So I still don't know what I could do about this
    Get this small utility to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
    Supports C++ and VB out of the box, but can be configured for other languages.

  13. #13
    Join Date
    Mar 2002
    Location
    California
    Posts
    1,582
    Code:
    STDMETHOD(Refresh)()
    {
        HWND hwnd = GetHwnd();
        ::RedrawWindow(hwnd, 0, 0, RDW_UPDATENOW);
        return S_OK;
    }
    the call to GetHwnd() is actually a call to ATLBaseComObject<Base>::GetHwnd(), which does use the template parameter, so I believe the template parameter is really needed.

    I don't see any way away from this.

    Is this question academic, or do you really have a problem with executable size?

    Jeff

  14. #14
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588
    Part and part :/ The thing is that for the moment I only have 4 COM objects which use this, but I'm going to have about 20 to 30. The size of the OCX increases quite a bit each time I add a new one, so I'm trying different avenues of preventing this.

    the call to GetHwnd() is actually a call to ATLBaseComObject<Base>::GetHwnd(), which does use the template parameter, so I believe the template parameter is really needed.
    Yes and no. I could actually derive a non-templated class CIntermediate from ATLBaseComObject<Base> and implement Refresh() in there, then derive CFinal from CIntermediate. Unfortunately ATL expects the parameter Base to be the final class in many cases :/

    Hum, or maybe I could find out which these cases are and deal with this. Then write all the stuff I can into a non-templated class and derive from the two. This could work
    Get this small utility to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
    Supports C++ and VB out of the box, but can be configured for other languages.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured