[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

__FUNCTION__ macro and CString problem

Posted on 2007-08-06
23
Medium Priority
?
2,202 Views
Last Modified: 2013-12-03
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
0
Comment
Question by:mrwad99
  • 13
  • 5
  • 4
  • +1
23 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 19638463
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
 
LVL 19

Author Comment

by:mrwad99
ID: 19638641
OK, cool.  So why does it work in a console application as-is, yet not in an MFC dialog app?
0
 
LVL 19

Author Comment

by:mrwad99
ID: 19638662
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
Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

 
LVL 86

Expert Comment

by:jkr
ID: 19638683
Hm, is the dialog app created as UNICODE or ANSI (and what's that for the console app)?
0
 
LVL 19

Author Comment

by:mrwad99
ID: 19638771
Yeah, I just checked.  Both are set to use UNICODE, and both use MFC in a shared DLL.  Confusing, isn't it?
0
 
LVL 86

Expert Comment

by:jkr
ID: 19638811
How are you using that in the dialog app?
0
 
LVL 30

Expert Comment

by:Axter
ID: 19638866
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
 
LVL 19

Author Comment

by:mrwad99
ID: 19638918
That works fine:

      T dg ( _T(" __FUNCTION__") );


Gives no compile error

?
0
 
LVL 19

Author Comment

by:mrwad99
ID: 19638926
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
 
LVL 30

Expert Comment

by:Axter
ID: 19638935
>>Does not work, as it is not a UNICODE string; same error

Now try the same string literal on the Console application.
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 19638947
Why not using

T dg ( CString( __FUNCTION__) );

for both?
0
 
LVL 19

Author Comment

by:mrwad99
ID: 19638958
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
 
LVL 30

Assisted Solution

by:Axter
Axter earned 500 total points
ID: 19638992
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
 
LVL 19

Author Comment

by:mrwad99
ID: 19639012
>> 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
 
LVL 19

Author Comment

by:mrwad99
ID: 19639021
>> 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
 
LVL 30

Expert Comment

by:Axter
ID: 19639031
>>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
 
LVL 19

Author Comment

by:mrwad99
ID: 19639046
Yeah, that compiles and works fine, even after a total rebuild.

?!
0
 
LVL 19

Author Comment

by:mrwad99
ID: 19639069
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
 
LVL 30

Expert Comment

by:Axter
ID: 19639253
>>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
 
LVL 19

Author Comment

by:mrwad99
ID: 19639388
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
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 19640773
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
 
LVL 19

Author Comment

by:mrwad99
ID: 19644142
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
 
LVL 19

Author Comment

by:mrwad99
ID: 19690848
Thanks all.
0

Featured Post

NFR key for Veeam Agent for Linux

Veeam is happy to provide a free NFR license for one year.  It allows for the non‑production use and valid for five workstations and two servers. Veeam Agent for Linux is a simple backup tool for your Linux installations, both on‑premises and in the public cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question