samn
samn

Reputation: 19

C++ C2440 Error, cannot convert from 'std::_String_iterator<_Elem,_Traits,_Alloc>' to 'LPCTSTR'

Unfortunately I have been tasked with compiling an old C++ DLL so that it will work on Win 7 64 Bit machines. I have zero C++ experience. I have muddled through other issues, but this one has stumped me and i have not found a solution elsewhere. The following code is throwing a C2440 compiler error.

The error: "error C2440: '' : cannot convert from 'std::_String_iterator<_Elem,_Traits,_Alloc>' to 'LPCTSTR'"

the code:

#include "StdAfx.h"
#include "Antenna.h"
#include "MyTypes.h"
#include "objbase.h"

const TCHAR* CAntenna::GetMdbPath()
{
    if(m_MdbPath.size() <= 0) return NULL;
    return LPCTSTR(m_MdbPath.begin());
}

"m_MdbPath" is defined in the Antenna.h file as string m_MdbPath;

Any assistance or guidance someone could provide would be extremely helpful. Thank you in advance. I am happy to provide additional details on the code if needed.

Upvotes: 0

Views: 2865

Answers (2)

PaulMcKenzie
PaulMcKenzie

Reputation: 35454

The solution:

const TCHAR* CAntenna::GetMdbPath()
{
    if(m_MdbPath.size() <= 0) return NULL;
    return m_MdbPath.c_str();
}

will work if you can guarantee that your program is using the MBCS character set option (or if the Character Set option is set to Not Setif you're using Visual Studio), since a std::string character type will be the same as the TCHAR type.

However, if your build is UNICODE, then a std::string character type will not be the same as the TCHAR type, since TCHAR is defined as a wide character, not a single-byte character. Thus returning c_str() will give a compiler error. So your original code, plus the tentative fix of returning std::string::c_str() may work, but it is technically wrong with respect to the types being used.

You should be working directly with the types presented to your function -- if the type is TCHAR, then you should be using TCHAR based types, but again, a TCHAR is a type that changes definition depending on the build type.

As a matter of fact, the code will fail miserably at runtime if it were a UNICODE build and to fix the compiler error(s), you casted to an LPCTSTR to keep the compiler quiet. You cannot cast a string pointer type to another string pointer type. Casting is not converting, and merely casting will not convert a narrow string into a wide string and vice-versa. You will wind up with at the least, odd characters being used or displayed, and worse, a program with random weird behavior and crashes.

In addition to this you never know when you really will need to build a UNICODE version of the DLL, since MBCS builds are becoming more rare. Going by your original post, the DLL's usage of TCHAR indicates that yes, this DLL may (or even has) been built for UNICODE.


There are a few alternate solutions that you can use. Note that some of these solutions may require you to make additional coding changes beyond the string types. If you're using C++ stream objects, they may also need to be changed to match the character type (for example, std::ostream and std::wostream)


Solution 1. Use a typedef, where the string type to use depends on the build type.

For example:

#ifdef UNICODE
   typedef std::wstring tchar_string;
#else
   typedef std::string tchar_string;
#endif

and then use tchar_string instead of std::string. Switching between MBCS and UNICODE builds will work without having to cast strin types, but requires coding changes.


Solution 2. Use a typedef to use TCHAR as the underlying character type in the std::basic_string template.

For example:

typedef std::basic_string<TCHAR> tchar_string;

And use tchar_string in your application. You get the same public interface as std::(w)string and this allows you to switch between MBCS and UNICODE build seamlessly (with respect to the string types).


Solution 3. Go with UNICODE builds and drop MBCS builds altogether

If the application you're building is a new one, then UNICODE is the default option (at least in Visual Studio) when creating a new application. Then all you really need to do is use std::wstring.

This is sort of the opposite of the original solution given of making sure you use MBCS, but IMO this solution makes more sense if there is only going to be one build type. MBCS builds are becoming more rare, and basically should be used only for legacy apps.

Upvotes: 1

AlexB
AlexB

Reputation: 78

std::string has a .c_str() member function that should accomplish what you're looking for. It will return a const char* (const wchar_t* with std::wstring). std::string also has an empty() member function and I recommend using nullptr instead of the NULL macro.

const TCHAR* CAntenna::GetMdbPath()
{
    if(m_MdbPath.empty()) return nullptr;
    return m_MdbPath.c_str();
}

Upvotes: 2

Related Questions