Cannot construct CString from a char - c++

In VS2008, I try to construct a CString from a char, as follows:
CString str = CString(_T('A') + 5);
But will get the following compile error:
error C2440: '' : cannot convert from 'int' to 'CString'
I belive TCHAR and int is exchangable in C++, so why it refuses to accept the TCHAR type parameter to construct a CString?
The purpose of the line is to construct a CString with only one character _T('F'). Not to get "A5".
I try to understand how the compiler processes the code, as follows:
It will first promote _T('A') to an integer.
It will add the integer value of _T('A') by 5.
It will get a new integer and cannot find a way to convert it back to TCHAR, which can be used as input parameter for CString constructor.

The CstringT constructors that accept a char or a wchar_t are explicit. See the docs.
The explicit specifier in C++ means that the compiler is not allowed to do an implicit conversion of the parameter(s). See also explicit specifier.
Thus the compiler cannot (is not allowed to) implicitly convert the int value to char or wchar_t.
(Note that this depends on the flag _ATL_CSTRING_EXPLICIT_CONSTRUCTORS being set. Without the flag being set, the constructors are not explicit, but then it's ambiguous which constructor to chose.)
So you need to explicitly cast the parameter to char or wchar_t, depending on what you want:
CStringA str = CStringA(static_cast<char>('A' + 5));
or:
CStringW str = CStringW(static_cast<wchar_t>(L'A' + 5));

CString will not implicitly convert an int to CString. However you can try like so
CString str;
char c = 'A';
int i = 5;
str.Format(L"%c%d",c, i); // unicode assumed

Related

Error C2440 when compiling a library with meson

I have code C++ that I want to compile as a library using meson where I get 2 kinds of errors
error C2440: 'initializing': cannot convert from 'const wchar_t [19]'
to 'const PWCHAR'
-note: Conversion from string literal loses const qualifier (see /Zc:strictStrings)
error C2664: '... cannot convert argument 2 from 'const wchar_t [6]'
to 'PWSTR note: Conversion from string literal loses const qualifier (see /Zc:strictStrings)
winnt.h uses typedef for wchar_t:
typedef wchar_t WCHAR;
typedef WCHAR *PWCHAR;
If I do this in my code I get Error C2440:
const PWCHAR Tokens[] = { L"A", L"B", L"C", L"D" };
If I change my code that error disappears:
const wchar_t * Tokens[] = { L"A", L"B", L"C", L"D" };
I know in C, the type of a string literal is array of char, but in C++, it's array of const char which causes this error.
I also know it is possible to change Zc:strictStrings in VStudio. But since I compile my code with meson how would I get rid of that error using meson?
With the definition
const PWCHAR Tokens[] = { ... };
you declare that Tokens is an array of constant pointers. The data that those pointers are pointing to are not constant.
And as literal strings are constant you can't use them to initialize the array.
The working definition:
const wchar_t * Tokens[] = { ... };
Or the alternative
wchar_t const * Tokens[] = { ... };
Here you declare that Tokens is an array of (non-constant) pointers to constant wchar_t data. Which is correct for literal strings.
If you want to be portable and follow the C++ standard, using PWCHAR is simply not possible.
If you want the pointers themselves to be constant, you need to add another const qualifier for them:
wchar_t const * const Tokens[] = { ... };
// ^^^^^
// makes the pointers constant
// ^^^^^
// makes the data constant
Or as mentioned in a comment: Use std::wstring (and other standard C++ containers):
// Or std::array if the size if known and fixed at compile-time
std::vector<std::wstring> Tokens = { ... };

C2440: '=': cannot convert from 'const char [9]' to 'char*'

I am working on a Qt5 project written in C++. Building the project gives an error:
C2440: '=': cannot convert from 'const char [9]' to 'char*'
Which points to the line of code below:
port_name= "\\\\.\\COM4";//COM4-macine, COM4-11 Office
SerialPort arduino(port_name);
if (arduino.isConnected())
qDebug()<< "ardunio connection established" << endl;
else
qDebug()<< "ERROR in ardunio connection, check port name";
//the following codes are omitted ....
What is the problem here, and how can I correct it?
In C++, in contrast to C, string literals are const. So any pointer to such a string literal must be const, too:
const char* port_name = "\\\\.\\COM4"; // OK
// char* port_name = "\\\\.\\COM4"; // Not OK
String literals are constant data in C++ (compilers tend to store them in read-only memory when possible).
In C++11 and later, you can no longer assign a string literal directly to a pointer-to-non-const-char (char*) 1.
1: though some C++11 compilers may allow it as a non-standard extension for backwards compatibility, which may need to be enabled manually via compiler flag.
So, you need to declare port_name as a pointer-to-const-char instead (const char * or char const *). But then you will have to cast it back to a non-const char* when passing it to SerialPort():
const char *port_name = "\\\\.\\COM4";
SerialPort arduino(const_cast<char*>(port_name));
Or simply:
SerialPort arduino(const_cast<char*>("\\\\.\\COM4"));
The alternative is to declare port_name as a non-const char[] buffer, copy the string literal into it, and then pass it to SerialPort():
char port_name[] = "\\\\.\\COM4";
SerialPort arduino(port_name);

How to construct WebURL from std::wstring?

I am writing a Win32 application with Awesomium. According to the tutorial section I can load a local file inside my view:
WebURL url(WSLit("file:///C:/dev/project/util/ui/index.html"));
view_->web_view()->LoadURL(url);
This works as expected.
When I try to pass an std::wstring to WSList function:
std::wstring ui_path = L"file:///" + install_path + L"/util/ui/index.html";
WebURL url(WSLit(ui_path));
view_->web_view()->LoadURL(url);
I get a compiler error:
src/main.cc(52) : error C2664: 'Awesomium::WSLit' : cannot convert parameter 1 from
'std::wstring' to 'const char *' No user-defined-conversion operator available that can
perform this conversion, or the operator cannot be called
When I try to pass WSLit( ui_path.c_str() ) the compiler throws another error:
src/main.cc(52) : error C2664: 'Awesomium::WSLit' : cannot convert parameter 1 from
'const wchar_t *' to 'const char *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or
function-style cast
What is the right way to convert it to const char * type?
Edit:
From Awesomium documentation :
WSLit() is a special helper function that lets you declare WebString literals. Most of our API uses UTF-16 strings (wrapped with WebString) but we added WSLit() so you can declare ASCII C-strings with minimal fuss.
WSLit is meant to construct a WebString object from an ASCII string. Since you don't want to construct a WebString from ASCII, but rather have a UNICODE string from the beginning, you simply don't need to use WSLit at all.
The following line of code constructs a WebURL from a std::wstring:
WebURL url(WebString(ui_path.c_str()));
As pointed out by Remy Lebeau this may not compile for any given compiler or compiler settings. WebString has an explicit constructor taking a const wchar16*. Platform.h defines wchar16 as
typedef unsigned short wchar16;
Depending on your compiler and compiler settings, this may or may not be the same as wchar_t. When compiling with the Microsoft compiler using the command line option /Zc:wchar_t, wchar_t is interpreted as a native data type. This is a different type from unsigned short, and the explicit constructor of WebString requires an additional cast:
WebURL url(WebString(reinterpret_cast<const wchar16*>(ui_path.c_str())));
Implicitly invoking the conversion constructor of WebString using the following syntax is not possible, since it is declared explicit:
WebURL url(reinterpret_cast<const wchar16*>(ui_path.c_str()));
If the question is "convert std::wstring to const char*", I usually use this function and it works fine:
std::string wstringToString(const std::wstring& in){
std::string result(in.begin(), in.end());
return result;
}
And then, you can get char* by calling result.c_str();
Try this one:
std::wstring ui_path = L"file:///" + install_path + L"/util/ui/index.html";
std::string cui_path( ui_path.begin(), ui_path.end() );
WebURL url(WSLit(cui_path));
view_->web_view()->LoadURL(url);
However, IMHO, if Awesomium is intended to run under Windows, the WSLit constructor should support either a std::wstring or wchar_t * argument.

How to convert char* to LPCWSTR?

I know this has already been discussed in several questions on SO, but none of those solutions have worked for me.
I start with a char* because this is for a DLL that will be called from VBA, and char* is necessary for VBA to pass a string to the DLL.
I need to return a LPCWSTR because that's the input parameter for the API function I'm trying to call, and I can't enable casting by switching from Unicode to multi-byte character set in the Properties window, because the API has this code:
#if !defined(UNICODE) && !defined(NOUNICODE)
#error UNICODE is not defined. UNICODE must be defined for correct API arguments.
#endif
I tried this:
LPCWSTR convertCharArrayToLPCWSTR(char* charArray)
{
const char* cs=charArray;
wchar_t filename[4096] = {0};
MultiByteToWideChar(0, 0, cs[1], strlen(cs[1]), filename, strlen(cs[1]));
}
which gave these errors:
error C2664: 'strlen' : cannot convert parameter 1 from 'const char' to 'const char *'
error C2664: 'MultiByteToWideChar' : cannot convert parameter 3 from 'const char' to 'LPCCH'
I tried this (same function header), loosely adapted from this post:
size_t retVal;
const char * cs = charArray;
size_t length=strlen(cs);
wchar_t * buf = new wchar_t[length](); // value-initialize to 0 (see below)
size_t wn = mbsrtowcs_s(&retVal,buf,20, &cs, length + 1, NULL);
return buf;
This compiled ok, but when I passed it an example string of "xyz.xlsx", mbsrtowcs_s() set buf to an empty string: L""
So, how do I make this conversion?
Following Hans Passant's advice regarding pointers to local variables, I worked out this approach, which seems to work well:
wchar_t *convertCharArrayToLPCWSTR(const char* charArray)
{
wchar_t* wString=new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
return wString;
}
I'm aware that the use of new requires memory management, which I perform in the function that calls this one.
Since cs is a const char*, cs[1] is a const char. C++ won't convert it to a pointer for you, because in most cases that doesn't make sense.
You could instead say &cs[1] or cs+1 if the intent is to skip the first char. (That's what you're doing when you pass a pointer to the 1th element; in C++, indexes start at 0.) If the intent is to pass the whole string, then just pass cs.

Setting CHAR16* to a #define string?

I'm a little confused on the proper way to do this. I have a #DEFINE that contains a string, and I have a CHAR16* that I want to set to that string. How would I properly do this? I've tried:
#DEFINE MYSTRING "HELLO"
CHAR16* THISONE;
THISONE = MYSTRING;
Why won't this work? I want to be able to print out the string in THISONE. I get a compiler warning regarding incompatible types. I'm sure I'm missing something small?
You're defining a narrow string literal "HELLO", but trying to use a CHAR16 pointer to point to it. That's not a compatible assignment. As clang says:
example.cpp:9:13: error: assigning to 'wchar_t *' from incompatible type
'const char [6]'
THISONE = MYSTRING;
^ ~~~~~~~~
1 error generated.
(I changed the type from CHAR16 * to wchar_t * since I'm not on windows - the semantics are the same).
To fix it, you need to add an L in front of the string constant:
#define MYSTRING L"HELLO"
And then it will compile. In C, you're done. In C++, however, you will probably still get a warning:
example.cpp:9:15: warning: conversion from string literal to 'wchar_t *' is
deprecated [-Wdeprecated-writable-strings]
THISONE = MYSTRING;
^
example.cpp:3:18: note: expanded from macro 'MYSTRING'
#define MYSTRING L"HELLO"
^
1 warning generated.
Change the definition to:
const wchar_t *THISONE;
To fix that warning. I guess in your case that would be:
const CHAR16 *THISONE;
Editorial note - in the future, please show your real code. #DEFINE (with the capital letters) isn't valid C or C++.
You probably want something like:
// Update: As carl points out, there is more to this for wide chars
const CHAR16* THISONE = MYSTRING;
You can explore more about c-strings here and also from within this very site.
You probably want to assign it as a global variable. In this case you need:
#define MYSTRING "HELLO"
CHAR* THISONE = MYSTRING;
or
#define MYSTRING L"HELLO"
CHAR16* THISONE = MYSTRING;
If assignment is in function (main() or other) you can make assignment not at the same place as variable creation.
Actually, I'm not sure if there is such a type "CHAR16"