Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / Managed C++ / December 2006

Tip: Looking for answers? Try searching our database.

Problem with BEGIN_TEMPLATE_MESSAGE_MAP (long)

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
skydivergm@gmail.com - 13 Dec 2006 13:01 GMT
Hi,

Consider the following code:

---

template <class T>
class TMyCWndWrapper : public T
{
public:
    afx_msg void OnEnable(BOOL bEnable)
    {
        // For the sake of simplicity I'll just call the base class imp.
        T::OnEnable(bEnable);
    }

    DECLARE_MESSAGE_MAP()
};

// Define a custom template IMPLEMENT_MESSAGE_MAP
#define WND_TEMPLATE_IMPLEMENT_MESSAGE_MAP(baseClass) \
    BEGIN_MESSAGE_MAP(TMyCWndWrapper< baseClass >, baseClass) \
    ON_WM_ENABLE() \
END_MESSAGE_MAP()

WND_TEMPLATE_IMPLEMENT_MESSAGE_MAP( CListBox );
WND_TEMPLATE_IMPLEMENT_MESSAGE_MAP( CListCtrl );

---

This code compiles just fine in VC6.
In VC8, I get the following error:
error C2906: 'const AFX_MSGMAP
*TMyCWndWrapper<T>::GetThisMessageMap(void)' : explicit specialization
requires 'template <>'

So I went on and implemented my own BEGIN_TEMPLATE_MESSAGE_MAP and
added the "template <>" where needed.

When I compiled, I had a macro redefinition on
BEGIN_TEMPLATE_MESSAGE_MAP. It turns out that MFC already took care of
that, so I removed my implementation and used MFC's with the adjusted
line:
   BEGIN_TEMPLATE_MESSAGE_MAP(TMyCWndWrapper, baseClass , baseClass)

Now, if I define only the first line:
   WND_TEMPLATE_IMPLEMENT_MESSAGE_MAP( CListBox );

The code actually compiles, but if I add the other line:
   WND_TEMPLATE_IMPLEMENT_MESSAGE_MAP( CListCtrl );

Now I get the error:
error C2995: 'const AFX_MSGMAP *TMyCWndWrapper<T>::GetMessageMap(void)
const' : function template has already been defined.

My current status is that I re-implemented BEGIN_TEMPLATE_MESSAGE_MAP
as follows:

---
#undef BEGIN_TEMPLATE_MESSAGE_MAP
#define BEGIN_TEMPLATE_MESSAGE_MAP(theClass, type_name, baseClass) \
    PTM_WARNING_DISABLE \
    template <> \
    const AFX_MSGMAP* theClass< type_name >::GetMessageMap() const \
        { return GetThisMessageMap(); } \
        template <> \
        const AFX_MSGMAP* PASCAL theClass< type_name >::GetThisMessageMap() \
    { \
    typedef theClass< type_name > ThisClass; \
    typedef baseClass TheBaseClass; \
    static const AFX_MSGMAP_ENTRY _messageEntries[] = \
    {
---

The diff. between this one and MFC's is that I replaced:
      template < typename type_name >
with:
      template <>

---

The code now compiles just fine.
So, in case this helps someone, I'll be very happy.
Beyond that, if someone would like to explain what's going on here I
will be happy to receive an answer.
I don't understand what "template < typename type_name >" means.

   Cheers.
Ben Voigt - 13 Dec 2006 19:33 GMT
> ---
> #undef BEGIN_TEMPLATE_MESSAGE_MAP
[quoted text clipped - 24 lines]
> will be happy to receive an answer.
> I don't understand what "template < typename type_name >" means.

The difference is that your code implements a single specialized message map
each time, whereas the library code declares an entire family of message
maps using a template parameter.  With the library version, you aren't
actually specifying what the base class is... instead you are giving a name
to the base class which can be used inside the message map to declare
functions that use the base class, whatever it may be, in the argument list
or return type.

>    Cheers.
nospam2017@gmail.com - 14 Dec 2006 15:29 GMT
> The difference is that your code implements a single specialized message map
> each time, whereas the library code declares an entire family of message
[quoted text clipped - 3 lines]
> functions that use the base class, whatever it may be, in the argument list
> or return type.

I'm doing my best to understand what you wrote, but I'm having a hard
time connecting it to real life.
Can you please give a usage example to MFC's version of the macro? I'm
just missing its purpose.
Also, am I on the right track, or do you have a better idea for me to
solve my issue using standard macros instead of redefining it?

TIA.
Ben Voigt - 15 Dec 2006 16:11 GMT
>> The difference is that your code implements a single specialized message
>> map
[quoted text clipped - 13 lines]
> Also, am I on the right track, or do you have a better idea for me to
> solve my issue using standard macros instead of redefining it?

You have something along these lines you wrote:

// Define a custom template IMPLEMENT_MESSAGE_MAP
#define WND_TEMPLATE_IMPLEMENT_MESSAGE_MAP(baseClass) \
BEGIN_MESSAGE_MAP(TMyCWndWrapper< baseClass >, baseClass) \
ON_WM_ENABLE() \
END_MESSAGE_MAP()

WND_TEMPLATE_IMPLEMENT_MESSAGE_MAP( CListBox );
WND_TEMPLATE_IMPLEMENT_MESSAGE_MAP( CListCtrl );

With the MFC map, you get the per-class repetition for free as part of the
template behavior, no macro needed.

BEGIN_TEMPLATED_MESSAGE_MAP(TMyCWndWrapper, baseClass, baseClass) \
ON_WM_ENABLE()
END_MESSAGE_MAP()

defines the message map for TMyCWndWrapper<baseClass> for all needed values
of baseClass.  The compiler will instantiate the template for both
TMyCWndWrapper<CListBox> and TMyCWndWrapper<CListCtrl> if you have used them
anywhere.  This is far better than the macro because: it is type-safe and
error reporting is far better, and there is no need to maintain the list of
instances.

or to see why there need to be three arguments instead of two, add to the
above:
template <typename T>
class TMyDerivedWnd : TMyCWndWrapper<T> {};

BEGIN_TEMPLATED_MESSAGE_MAP(TMyDerivedWnd, baseClass,
TMyCWndWrapper<baseClass>) \
ON_WM_ENABLE()
END_MESSAGE_MAP()

> TIA.

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.