__FUNCTION__ macro and CString problem

Ah hello.

I have the following class and a call in an MFC application:

class T
{
public:
      T( const CString& lpszT )
      {
            m_str = lpszT;
      }
      CString m_str;
};


T dg ( __FUNCTION__ );


The compiler complains

'T::T(const CString &)' : cannot convert parameter 1 from 'const char [28]' to 'const CString &'

I then create a new win32 console application via VS 2005, add the same code and there is no complaint.  I thought it was something to do with me having to #include <atlstr.h>, so I did that in my MFC app without any luck.  When I step into the code in the console app, I can see that MultiByteToWideChar is being called underneath the hood.  So what is the problem with the MFC version?

TIA
LVL 19
mrwad99Asked:
Who is Participating?
 
jkrCommented:
Why not using

T dg ( CString( __FUNCTION__) );

for both?
0
 
jkrCommented:
The problem is the reference - the compiler would be able to use

class T
{
public:
      T( const CString lpszT )
      {
            m_str = lpszT;
      }
      CString m_str;
};

for an automatic conversion, using a reference requires you to pass a temp. object in a call

dg ( CString(__FUNCTION__) );

or a wrapper like

T dg ( const char* p ) {

  CString str(p);

  return dg(str);
}
0
 
mrwad99Author Commented:
OK, cool.  So why does it work in a console application as-is, yet not in an MFC dialog app?
0
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
mrwad99Author Commented:
i.e.

class T
{
public:
      T( const CString& lpszT )
      {
            m_str = lpszT;
      }
      CString m_str;
};

int main( int nArgc, TCHAR** lpszArgs )
{
      T dg ( __FUNCTION__ );
}

works without complaint.
0
 
jkrCommented:
Hm, is the dialog app created as UNICODE or ANSI (and what's that for the console app)?
0
 
mrwad99Author Commented:
Yeah, I just checked.  Both are set to use UNICODE, and both use MFC in a shared DLL.  Confusing, isn't it?
0
 
jkrCommented:
How are you using that in the dialog app?
0
 
AxterCommented:
Try replacing the __FUNCTION__ with an ANSI string literal, and see if you get the same compile error.



      T dg ( "This is a Test" );
0
 
mrwad99Author Commented:
That works fine:

      T dg ( _T(" __FUNCTION__") );


Gives no compile error

?
0
 
mrwad99Author Commented:
Doh.

      T dg ( " __FUNCTION__" );

Does not work, as it is not a UNICODE string; same error

error C2664: 'T::T(const CString &)' : cannot convert parameter 1 from 'const char [14]' to 'const CString &'
0
 
AxterCommented:
>>Does not work, as it is not a UNICODE string; same error

Now try the same string literal on the Console application.
0
 
mrwad99Author Commented:
I need to be able to log various function entry points.  So I use an automatic instance of this class to make note of what functions are entered and left:

class CFuncLogger
{
public:
      CFuncLogger ( const CString& strFunc );
      ~CFuncLogger();
private:
      CString m_strFunc;      // The name of the function we are logging a call to
};


CFuncLogger::CFuncLogger( const CString& strFunc )
: m_strFunc ( strFunc )
{
      g_myLog.Printf ( _T("Entering %s"), m_strFunc );
}

CFuncLogger::~CFuncLogger( )
{
      g_myLog.Printf ( _T("Leaving %s"), m_strFunc );
}

where g_myLog is a log class that writes to file etc etc.

I call this like this:

BOOL CDialogAppDlg::OnInitDialog()
{
      CDialog::OnInitDialog();

      CFuncLogger dg ( __FUNCTION__ );

      // ...

}
0
 
AxterCommented:
Why not overload your constructor.

class CFuncLogger
{
public:
      CFuncLogger ( const CString& strFunc );
      CFuncLogger ( const char* strFunc ); //****************overload constructor
      ~CFuncLogger();
private:
      CString m_strFunc;      // The name of the function we are logging a call to
};
0
 
mrwad99Author Commented:
>> Now try the same string literal on the Console application.

What the heck; that works!  How can it, when it is not a UNICODE string???

>> Why not using...

Well, my original constructor above took an LPCTSTR:

CFuncLogger::CFuncLogger( LPCTSTR lpszFuncName )

but when I came to compile it it did not like me passing __FUNCTION__ to it.  Examining the compiler error I realised that it was saying__FUNCTION__ is a single byte character array, and I was passing it to a wide character pointer (as I compile in Unicode).  So, I looked into how to convert a multi byte array into a wide array, but then after some research found that CString can do it for us:


CStringT& operator=( __in_z_opt PCYSTR pszSrc )
{
                  // ...
                  StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc);

which ends up calling

            ::MultiByteToWideChar(...)

So I tested this in a simple console application to save build time on my main project, and it worked.  Then I put it back into my MFC app and it did not work, hence the confusion!  Why is this same code path not being followed for my MFC app!
0
 
mrwad99Author Commented:
>> Why not overload your constructor.

Yeah, could do, but I would still like to know why it does work for a console app yet not for an MFC one
0
 
AxterCommented:
>>What the heck; that works!  How can it, when it is not a UNICODE string???
Are you really sure your console application is being compiled as a UNICODE app?

Try this to confirm it:
int main( int nArgc, TCHAR** lpszArgs )
{
      T dg ( L"This is UNICODE test" );  //Notice the L prefix
}
0
 
mrwad99Author Commented:
Yeah, that compiles and works fine, even after a total rebuild.

?!
0
 
mrwad99Author Commented:
Second test:

void F ( LPCTSTR s )
{
}

F ( L"sfgsafa");

works only with UNICODE defined; without UNICODE (i.e. Multibyte characters) the error  'F' : cannot convert parameter 1 from 'const wchar_t [8]' to 'LPCTSTR' as expected is displayed.
0
 
AxterCommented:
>>Yeah, that compiles and works fine, even after a total rebuild.

That is very strange......

They must not be using the same CString class.  The console CString class must have a const char* type as an argument in one of the overloaded constructors.
0
 
mrwad99Author Commented:
As I mentioned, my console application #includes <atlstr.h> whereas my MFC app doesn't.  The help states that this header file is for none MFC strings, but surely there should not be any difference in the two...
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
Have you tried
T( CString lpszT )
instead of
T( const CString& lpszT )

ie. Create a local instance of a CString instead of a reference to one.

re your original LPCTSTR why not have two versions - one for char* and one for wchar*
0
 
mrwad99Author Commented:
That does not work either Andy.  And yeah, I could have two versions, but that still does not solve the confusion as to why this works in a console app yet not an MFC app...
0
 
mrwad99Author Commented:
Thanks all.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.