C++ override quotes - string

Ok, so I'm using C++ to make a library that'd help me to print lines into a console.
So, I want to override " "(quote operators) to create an std::string instead of the string literal, to make it easier for me to append other data types to that string I want to output.
I've seen this done before in the wxWidgets with their wxString, but I have no idea how I can do that myself.
Is that possible and how would I go about doing it?
I've already tried using this code, but with no luck:
class PString{
std::string operator""(const char* text, std::size_t len) {
return std::string(text, len);
}
};
I get this error:
error: expected suffix identifier
std::string operator""(const char* text, std::size_t len) {
^~
which, I'd assume, want me to add a suffix after the "", but I don't want that. I want to only use ""(quotes).
Thanks!

You can't use "" without defining a suffix. "" is a const char* by itself either with a prefix (like L"", u"", U"", u8"", R"()") or followed by suffixes like (""s, ""sv, ...) which can be overloaded.

The way that wxString works is set and implicit constructor wxString::wxString(const char*); so that when you pass "some string" into a function it is essentially the same as wxString("some string").
Overriding operator ""X yields string literals as the other answer.

Related

Why is using tinyxml2-ex::text returning corrupted text?

I am trying to use the tinyxml2-ex library to read some XML data.
When I try using it's specific API call:
const CString strNameToUse(tinyxml2::text(pAssign).c_str());
The resulting string loses things like accents. In the end I have reverted to my original approach with the UTF8 handling:
const CString strNameToUse(CA2CT(pAssign->GetText(), CP_UTF8));
This works fine. Does anyone know why the tinyxml2-ex::text approach fails? Note that it is permissible to the use the tinyxml2 namespace.
The referred to library is using std::string and does it like this:
// helper function to get element text as a string, blank if none
inline std::string text (const XMLElement * element)
{
if (!element)
throw XmlException ("null element"s);
if (auto value = element -> GetText())
return std::string (value);
else
return ""s;
}
The library author explained (GitHub discussion:
It's because tixml2ex::text (see line 465 in tixml2ex.h) does this:
if (auto value = element -> GetText())
return std::string (value);
which will corrupt any string containing characters outside ASCII 127.

How would I populate a vector with all the elements from a List of type system string while converting it to std::string?

I am trying to understand lambda functions better and would like some example of how I could add to a vector while converting System.String^ to std::string with such a Lambda example (If I am able to).
My current foreach:
List<String^>^ names = //Returning 'System.String' List from C#
for each (System::String^ name in names)
{
std::string convertedString = msclr::interop::marshal_as< std::string >(name);
nameObjects.push_back(MyObject(convertedString, "test"));
}
But I would like to extend it to something like this (My best guess but I am missing the logic to convert each element of "names" to a single string, this is where a Lambda would help me):
std::vector<nameObjects> testObjects{ std::begin(msclr::interop::marshal_as< std::string >(names)), std::end(msclr::interop::marshal_as< std::string >(names)) };
Alright, I figured out a way to make this work...it requires using the obscure cliext classes.
First, create a cliext::vector, there is an overload with takes an IEnumerator.
cliext::vector<String^> v_names(names);
Now, you can use cliext::transform() (not std::transform) to do STL-style iteration, and create MyObject instances with a lambda
std::vector<MyObject> testObjects;
cliext::transform(v_names.begin(), v_names.end(), std::back_inserter(testObjects), [](String^ name)
{
std::string convertedString = msclr::interop::marshal_as< std::string >(name);
return MyObject(convertedString, "test");
});

How to know if wstring can be safely (no data loss) converted to string?

So I already know how to convert wstring to string (How to convert wstring into string?).
However, I would like to to know whether it is safe to make the conversion, meaning, the wstring variable does not contain any characters that are not supported in string type.
strings can hold any data, if you use the right encoding. They are just sequences of bytes. But you need to check with your particular encoding / conversion routine.
Should be simply a matter of round-tripping. An elegant solution to many things.
Warning, Pseudo-code, there is no literal convert_to_wstring() unless you make it so:
if(convert_to_wstring(convert_to_string(ws)) == ws)
happy_days();
If what goes in comes out, it is non-lossy (at least for your code points).
Not that its the most efficient solution, but should allow you to build from your favorite conversion routines.
// Round-trip and see if we lose anything
bool check_ws2s(const std::wstring& wstr)
{
return (s2ws(ws2s(str)) == wstr);
}
Using #dk123's conversions for C++11 at How to convert wstring into string? (Upvote his answer here https://stackoverflow.com/a/18374698/257090)
wstring s2ws(const std::string& str)
{
typedef std::codecvt_utf8<wchar_t> convert_typeX;
std::wstring_convert<convert_typeX, wchar_t> converterX;
return converterX.from_bytes(str);
}
string ws2s(const std::wstring& wstr)
{
typedef std::codecvt_utf8<wchar_t> convert_typeX;
std::wstring_convert<convert_typeX, wchar_t> converterX;
return converterX.to_bytes(wstr);
}
Note, if your idea of conversion is truncating the wide chars to chars, then it is simply a matter of iterating and checking that each wide char value fits in a char. This will probably do it.
WARNING: Not appropriate for multibyte encoding.
for(wchar_t& wc: ws) {
if(wc > static_cast<char>::(wc))
return false;
}
return true;
Or:
// Could use a narrowing cast comparison, but this avoids any warnings
for(wchar_t& wc: ws) {
if(wc > std::numeric_limits<char>::max())
return false;
}
return true;
FWIW, in Win32, there are conversion routines that accept a parameter of WC_ERR_INVALID_CHARS that tells the routine to fail instead of silently dropping code points. Non-standard solutions, of course.
Example: WideCharToMultiByte()
http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130(v=vs.85).aspx

How to convert string to LPSTR in WinAPI function which stores output in string

I am trying to store some contents into a string variable by passing it as a parameter in various types of Windows API functions which accepts variable like char *.
For example, my code is:-
std::string myString;
GetCurrentDirectoryA( MAX_PATH, myString );
Now how do I convert the string variable to LPSTR in this case.
Please see, this function is not meant for passing the contents of string as input, but the function stores some contents into string variable after execution. So, myString.c_str( ) is ruled out.
Edit: I have a workaround solution of removing the concept of string and replacing it with something like
char myString[ MAX_PATH ];
but that is not my objective. I want to make use of string. Is there any way possible?
Also casting like
GetCurrentDirectoryA( MAX_PATH, ( LPSTR ) myString );
is not working.
Thanks in advance for the help.
Usually, people rewrite the Windows functions they need to be std::string friendly, like this:
std::string GetCurrentDirectoryA()
{
char buffer[MAX_PATH];
GetCurrentDirectoryA( MAX_PATH, buffer );
return std::string(buffer);
}
or this for wide char support:
std::wstring GetCurrentDirectoryW()
{
wchar_t buffer[MAX_PATH];
GetCurrentDirectoryW( MAX_PATH, buffer );
return std::wstring(buffer);
}
LPTSTR is defined as TCHAR*, so actually it is just an ordinary C-string, BUT it depends on whether you are working with ASCII or with Unicode in your code. So do
LPTSTR lpStr = new TCHAR[256];
ZeroMemory(lpStr, 256);
//fill the string using i.e. _tcscpy
const char* cpy = myString.c_str();
_tcscpy (lpStr, cpy);
//use lpStr
See here for a reference on _tcscpy and this thread.
Typically, I would read the data into a TCHAR and then copy it into my std::string. That's the simplest way.

Listing files in directory

I have created a windows form in c++ which, upon a button click, opens a dialog box for folder selection.
Now what I would like to do is get the list of files in that directory so that I can process them one by one.
I have googled it in many ways, and found many ways which include external libraries (such as boost and diren.h). I would not like to use external resources, but the ones at my disposal, the default ones.
I've read about FindFirstFile and FindNextFile, but couldnt get that combination to work.
Could you please assist?
Thanks a lot,
Idan.
Here is the updated code:
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
FolderBrowserDialog^ folderBrowserDialog1 = gcnew FolderBrowserDialog;
if (folderBrowserDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
String ^ selected = folderBrowserDialog1->SelectedPath;
selected += "\\*";
char* stringPointer = (char*) Marshal::StringToHGlobalAnsi(selected).ToPointer();
hFind = FindFirstFile((LPCWSTR)stringPointer, &FindFileData);
while(hFind != INVALID_HANDLE_VALUE)
{
printf("Found file: %s\r\n", FindFileData.cFileName);
if(FindNextFile(hFind, &FindFileData) == FALSE)
break;
}
}
You obviously compile for UNICODE (wide char) since you need to cast the newStr for the lpFileName parameter of FindFirstFile. But since you pass an ANSI string, you probable won't get a useful result. Youd didn't write, what you expect to find.
In the code beforer FindFirstFile you manually convert the SelectedPath value to ANSI char. That makes no sense, when you need a wide char string anyway. Get the LPCWSTR from the String selected with the StringToHGlobalUni method. This looks somehow like this (not tested):
LPCWSTR stringPointer = Marshal::StringToHGlobalAnsi(selected).ToPointer();
hFind = FindFirstFile(stringPointer, &FindFileData);
In general: Don't use casts except when you need to adapt a bad designed interface. Use it only when you know exactly what you are doing.
Further you don't check the hFind result of FindFirstFile. It will be INVALID_HANDLE_VALUE if you pass a pointer to the wrong string format.

Resources