qvariant_cast<std::string> returns empty string - c++

I am using QT 5.7 and MVSC - 2010 (yes, it is old, but I have to due to project)
I have a template function
template<T>
T foo (QString qs)
{
return qvariant_cast<T>(qs);
}
If I make
void main()
{
std::string str = "42"
QString qss = QString::fromStdString(str);
std::string another_str = foo<std::string>(qss );
}
Then another_str will be "";
While toStdString method works perfectly. What is the problem of qvariant_cast?
P.S. I have declared qt meta type, so qvariant_cast is compling, but returning empty string.

According to the manual call qss.canConvert<std::string>() to find out whether a type can be converted. If the value cannot be converted, a default-constructed value will be returned. It is your case, the empty std::string is returned.

Related

How do I convert a std::string to System.String in C++ with Il2CppInspector?

I am using Il2CppInspector to generate scaffolding for a Unity game. I am able to convert System.String (app::String in Il2CppInspector) to std::string using the functions provided below.
How would I reverse this process; how do I convert a std::string to System.String?
helpers.cpp
// Helper function to convert Il2CppString to std::string
std::string il2cppi_to_string(Il2CppString* str) {
std::u16string u16(reinterpret_cast<const char16_t*>(str->chars));
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(u16);
}
// Helper function to convert System.String to std::string
std::string il2cppi_to_string(app::String* str) {
return il2cppi_to_string(reinterpret_cast<Il2CppString*>(str));
}
In short, I am looking for a function that takes in a std::string and returns an app::String
// Helper function to convert std::string to System.String
app::String string_to_il2cppi(std::string str) {
// Conversion code here
}
The accepted answer is actually wrong, there is no size parameter and copying stops at the first null byte (0x00) according to the MSDN documentation.
The following code fixes these problems and works correctly:
app::String* string_to_il2cppi(const std::string& string)
{
const auto encoding = (*app::Encoding__TypeInfo)->static_fields->utf8Encoding;
const auto managed_string = app::String_CreateStringFromEncoding((uint8_t*)&string.at(0), string.size(), encoding, nullptr);
return managed_string;
}
A quote from djkaty:
To create a string, you cannot use System.String‘s constructors –
these are redirected to icalls that throw exceptions. Instead, you
should use the internal Mono function String.CreateString. This
function has many overloads accepting various types of pointer and
array; an easy one to use accepts a uint16_t* to a Unicode string and
can be called as follows [...]
Export Il2CppInspector with all namespaces, which will give you access to Marshal_PtrToStringAnsi.
app::String* string_to_il2cppi(std::string str) {
return app::Marshal_PtrToStringAnsi((void*)&str, NULL);
}
Limitation: do not attempt to convert a string with null terminators inside of them example:
std::string test = "Hello\0world";
Use BullyWiiPlaza's solution if this is an issue for you.

Cannot use std::string variable in RapidJSON function call

I am all new to C++ and am running into an issue. I am using rapidJSON to create JSON documents.
void setKeyValue() {
Value obj(kObjectType);
Value key("key");
Value val(42);;
obj.AddMember(key, val, d.GetAllocator());
}
Works as expected. But when I try to replace the call to key to make it use a passed in param, like so:
void setKeyValue(string myKey) {
Value obj(kObjectType);
Value key(myKey);
Value val(42);;
obj.AddMember(key, val, d.GetAllocator());
}
The myKey in Value key(myKey) get a red curly underling in Visual Studio saying the following:
What is causing this and how can I solve it?
You don't get support for std::string by default. rapidJSON requires you to specify you want std::string support.
#define RAPIDJSON_HAS_STDSTRING 1
Only then is this constructor you're using valid:
GenericValue (const std::basic_string< Ch > &s, Allocator &allocator)
JSON library you are using seems that doesn't work with string objects from standard library, but it works with const char*.
So you must convert string object to char* with the method c_str():
void setKeyValue(string myKey) {
Value obj(kObjectType);
Value key((char*)myKey.c_str());
Value val(42);;
obj.AddMember(key, val, d.GetAllocator());
}

QVariant conversion doesn't recognize std::string called by my template

I have a function in a class header ("frame.h") that's supposed to convert a QString to a generic type, initializing it to a default value if the QString is empty, shown below.
template <typename T>
static void setStat(T &val, QString &temp)
{
QVariant qv(temp);
if (temp == "")
val = T();
else
val = qv.value<T>();
}
When I call this (which has my only instance of a QVariant) I get the following two errors:
Type is not registered, please use the Q_DECLARE_METATYPE macro to make it
known to Qt's meta-object system (compiling source file item.cpp)
'qt_metatype_id': is not a member of 'QMetaTypeId<T>'
In the file mentioned in the first error ("item.cpp"), I call setStat() once and only once, in the code below, which is in the class constructor.
string temp1 = "";
Frame::setStat(temp1, vec[5]);
desc = temp1;
It's probably worth mentioning that this is in VS2017 with the Qt extension. As I understand it, the error is telling me that std::string is an unrecognized type. Is this normal behavior? How do I fix this?
Even with registration for QVariant, QString doesn't convert freely to QString.
You might add overload instead:
static void setStat(std::string &val, QString &temp)
{
val = temp.toStdString();
}

Object "is not a structure or union" if temporary is passed to constructor

I've not seen this specific oddity of C++ before and it's causing me a bit of confusion.
I have the following class:
class KeyValuesParser
{
public:
explicit KeyValuesParser(const QByteArray &input);
QJsonDocument toJsonDocument(QString* errorString = nullptr);
// ...
};
And I'm trying to use it like so in a Qt unit test:
const char* testData = "...";
KeyValuesParser parser(QByteArray(testData));
QJsonDocument doc = parser.toJsonDocument();
This gives the following compile error:
Member reference base type 'KeyValuesParser(QByteArray)' is not a structure or union.
However, if I create the byte array on the stack and then pass it in, instead of passing in a temporary, everything compiles fine:
const char* testData = "...";
QByteArray testByteArray(testData)
KeyValuesParser parser(testByteArray);
QJsonDocument doc = parser.toJsonDocument();
I thought this might have been some weird black magic that required the explicit keyword (which is why I added it), but that didn't make any difference. Can anyone explain what's going on here?
EDIT: I've been referred to another question as being a duplicate and I think it almost is, but there's some most-vexing-parse confusion on this question that I think merits the extra discussion.
NB. This is addition to Jonas' answer near me.
What are you trying to do is to bind rvalue to lvalue reference, this is not allowed in C++ standard. In your second example - you correctly pass lvalue via reference, that's why it's working.
Binding rvalue to lvalue reference is Visual C++ extension, g++ cannot do it at all, clang can do it with -fms-extensions
The line
KeyValuesParser parser(QByteArray(testData));
is not an object declaration. It’s a function declaration of a function returning a KeyValuesParser and taking a QByteArray argument.
This is called Most Vexing Parse (link goes to wikipedia, you’ll find plenty on StackOverflow too). To keep it short, when in doubt, the C++ standard prefers a function declaration, because otherwise it would be hard to declare functions at all.
As mentioned, this is a "most vexing parse" problem. c++11 brought us two solutions: auto and brace initialisation:
// use auto to turn the expression unambiguously into an rvalue
// without having to mention the class name twice
int main()
{
const char* testData = "...";
auto parser = KeyValuesParser(QByteArray(testData));
auto doc = QJsonDocument(parser.toJsonDocument());
}
// or use brace initialisation to avoid the parse ambiguity
//
int main2()
{
const char* testData = "...";
KeyValuesParser parser{ QByteArray(testData) };
QJsonDocument doc{ parser.toJsonDocument() };
}
// another solution:
const char* testData = "...";
auto doc = QJsonDocument(KeyValuesParser(QByteArray(testData)).toJsonDocument());
// yet another
const char* testData = "...";
auto doc = QJsonDocument { KeyValuesParser { QByteArray(testData) }.toJsonDocument() };

not able to return QString from c++ function to PERL function by using SWIG

I have c++ code (Includes Qt also), i want to call those functions by using Perl.
Which we can do by using SWIG, so I have implemented interfaces and did all the stuff need to use them in Perl script.
I have a function in c++ which returns a QString value,
QString get_string()
{
return QString("mystring");
}
I have written one more class which will be used in perl script where i have a function which calls this get_string() function and returns const char*.
const char* get_const_string()
{
QString str = get_string();
**//here I print str and str .toLocal8Bit().constData()
//both are printing the text which i shoud get here**
return str.toLocal8Bit().constData();
//here I have tried diff combinations also, as
// return str.toStdString().c_str();
}
The problem is, in get_const_string() function, I could get the string I wanted, but when I call this function in my perl script, I am getting undefine value i.e null string
.
Any idea, what is the problem here ??
I am using perl5, Qt4.8.4
Thanks in advance.
if you cant use a QString return value, maybe you can use std::string.
if both fail and you do not have limitations, you could do some dirty trick:
QString get_string()
{
static QByteArray arr;
QString str = getString();
arr = str.toLocal8Bit();
return arr.constData();
}
note that the arr variable will not be free'd untill your app is running
edit: found a possible solution to just use std::string ... string arguments are not recognized by SWIG