I'm learning the internal of CppWinRT
struct App : ApplicationT<App,IXamlMetadataProvider>
{
App()
{
IInspectable ins = *this; // A
cout << to_string(get_class_name(ins)) << endl;
}
...
}
why the output is Windows.UI.Xaml.IApplicationOverrides? In my understanding, code at A should fail, since there is no conversion operator defined in producers, that is, no such thing like
// base.h (v2.0.190620.2 line 5707)
operator producer_ref<Windows::Foundation::IInspectable> const() const noexcept
{...}
Please help me to figure out the conversion path. Many thanks!!!
Related
I have a custom class Dummy which I want to send as an object using Dynamic Replica in Qt6. I'm able to send the class but it's being transferred as QVariant which I'm not able to extract(or cast) from QVariabnt object.
Below is my implementation:
Dummy.h file
#ifndef CLIENT_DUMMY_H
#define CLIENT_DUMMY_H
#include <QtCore/qobject.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qvariant.h>
#include <QtCore/qmap.h>
#include <QtCore/qmetatype.h>
#include <QtRemoteObjects/qremoteobjectnode.h>
#include <QtRemoteObjects/qremoteobjectsource.h>
#include <QtCore>
class Dummy {
Q_GADGET
Q_PROPERTY(QString m_name READ name WRITE setName)
public:
Dummy(){}
explicit Dummy(QString str) : m_name(str) {}
QString name() const {
return m_name;
}
void setName(QString str){
m_name = str;
}
~Dummy() = default;
private:
QString m_name;
};
Q_DECLARE_METATYPE(Dummy)
inline QDataStream &operator<<(QDataStream &ds, const Dummy &obj) {
QtRemoteObjects::copyStoredProperties(&obj, ds);
return ds;
}
inline QDataStream &operator>>(QDataStream &ds, Dummy &obj) {
QtRemoteObjects::copyStoredProperties(ds, &obj);
return ds;
}
inline bool operator==(const Dummy &left, const Dummy &right) Q_DECL_NOTHROW {
return left.name() == right.name();
}
inline bool operator!=(const Dummy &left, const Dummy &right) Q_DECL_NOTHROW {
return !(left == right);
}
inline QDebug operator<<(QDebug dbg, const Dummy &obj) {
dbg.nospace() << "Dummy(" << "m_name: " << obj.name() << ")";
return dbg.maybeSpace();
}
The class is present at both sides server as well as client.
.rep file
class Interface {
PROP(Dummy dummy);
[...removed extra code]
}
Server method sending data to client:
void send() {
Dummy dummy("DummyString");
setDummy(dummy);
}
Client side file:
Inside constructor:
QObject::connect(reptr.data(), SIGNAL(dummyChanged(Dummy)), this, SLOT(receiveDummy(Dummy)));
void DynamicClient::receiveDummy(Dummy dummy) {
if(reptr.data()->isReplicaValid()){
QVariant variant = reptr.data()->property("dummy");
qDebug() << variant;
}
}
But when object from server to client is sent, qDebug() prints below:
QVariant(Dummy, QVariant(QString, "DummyString"))
I'm not able to extract Dummy Object from Qvariant object.
I've tried registering my custom type using qRegisterMetaType() as well but still it didn't work. Apart from that, I've used qvariant_cast and variant.value() but I printed the value I get some random character each time.
Thanks in advance. I can post more code if required.
Turns out I was not registering the Dummy class on client side due to which client was not able to recognize the type.
qRegisterMetaType needs to be used at both ends.
I use googletest as the main testing framework for a Qt project. QAbstractItemModelTester helps catching the most common errors in custom item model classes but I don't know how to integrate the reported failures(QTest) in a googletest unit test.
I didn't find any direct way to do this, but this is what I've done to have assertion for testing errors in QAbstractItemModelTester:
class AssertNoQtLogWarnings
{
static void messageHandlerTest(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
static bool NO_WARNING_MSG = true;
QByteArray localMsg = msg.toLocal8Bit();
const char* file = context.file ? context.file : "";
const char* function = context.function ? context.function : "";
switch (type) {
case QtDebugMsg:
fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
break;
case QtInfoMsg:
fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
break;
case QtWarningMsg:
EXPECT_EQ(false, NO_WARNING_MSG) << msg.toStdString();
break;
case QtCriticalMsg:
EXPECT_EQ(false, NO_WARNING_MSG) << msg.toStdString();
break;
case QtFatalMsg:
EXPECT_EQ(false, NO_WARNING_MSG) << msg.toStdString();
break;
}
}
public:
AssertNoQtLogWarnings()
{
qInstallMessageHandler(messageHandlerTest);
}
~AssertNoQtLogWarnings()
{
//Install default message handler
qInstallMessageHandler(nullptr);
}
};
TEST(QAbstractItemModel, QAbstractItemModel)
{
//RAII object. Any warning, critical or fatal message produced in this context
//will produce a GTest fail assertion
AssertNoQtLogWarnings logQtTest;
MyAbstractItemModel model;
QAbstractItemModelTester tester(&model, QAbstractItemModelTester::FailureReportingMode::Warning);
}
Given the following C++/CLI program:
#pragma managed(push, off)
class FooBar
{
FooBar(const FooBar& that) { *this = that; }
const FooBar& operator =(const FooBar& that);
};
#pragma managed(pop)
int main()
{
return 0;
}
Gives the following linker output:
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "private: class FooBar const & __thiscall FooBar::operator=(class FooBar const &)" (??4FooBar##AAEABV0#ABV0##Z) referenced in function "private: __thiscall FooBar::FooBar(class FooBar const &)" (??0FooBar##AAE#ABV0##Z) ConsoleApplication1 C:\Users\SomeUser\Documents\Visual Studio 2019\Projects\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.obj 1
But the following C++ program does not:
class FooBar
{
FooBar(const FooBar& that) { *this = that; }
const FooBar& operator =(const FooBar& that);
};
int main()
{
return 0;
}
The reason I need this to work is because I'm including a header file which is beyond my control that does this. Although I never need to use the copy constructor or the assignment operator.
Compiled using v142 platform toolset.
I have project which I am compiling with /clr. I have a class like below..
ref class A
{
public:
void CheckValue(void * test);
typedef ref struct val
{
std::string *x;
}val_t;
};
in my implementation I ahve to use something like below..
void A::CheckValue(void *test)
{
a::val_t^ allVal = (a::val_t^)test;
}
in my main I have used like..
int main()
{
A^ obj = gcnew A();
a::val_t valObj = new std::string("Test");
obj->CheckValue((void*)valObj);
}
I am getting type cast error and two places -
obj->CheckValue((void*)valObj);
and at
obj->CheckValue((void*)valObj);
error C2440: 'type cast' : cannot convert from 'void*' to 'A::val_t ^'
This snippet is just to show behavior at my end and I ahve to use it this way only. Earlier I was running it using non /clr so it compiled fine.
Now question I have how can I make this type casting work in C++/CLI type project?
Replace void * with Object^. You can also write a generic version of CheckValue but then there is not much point of having a weak-typed parameter when you have the type in the generic parameter.
A reference handle represents an object on the managed heap. Unlike a native pointer, CLR could move the object around during a function call, so the behavior of a pointer and a reference handle is different, and a type cast would fail. You can also pin the object being referenced using pin_ptr if you really need a void* so CLR would not be moving the object during the function call.
Here is how I would get around the limitation you are seeing, just remove the struct from the managed object, since it contains native pointer types.
struct val_t
{
char* x;
};
ref class A
{
public:
void CheckValue(void* test);
};
void A::CheckValue(void* test)
{
val_t* allVal = (val_t*)test;
}
int main()
{
A^ obj = gcnew A();
val_t valObj;
valObj.x = "Test";
obj->CheckValue((void*)&valObj);
}
Now, if you absolutely need the struct to be managed, here is how to do it:
ref class A
{
public:
void CheckValue(void * test);
value struct val_t
{
char* x;
};
};
void A::CheckValue(void *test)
{
a::val_t* allVal = (a::val_t*)test;
}
int main()
{
A^ obj = gcnew A();
a::val_t valObj;
valObj.x = "Test";
pin_ptr<a::val_t> valPin = &valObj;
obj->CheckValue((void*)valPin);
}
I have spotted something like this in code:
void foo(IList<int>^ const & list ) { ... }
What does this ^ const& mean? I looked in the C++/CLI specification, but found no comments on making constant tracking references, nor the ^& combo.
Is this legal?
This code was probably written by a C++ programmer that used common C++ idiom to write C++/CLI. It is quite wrong, passing a reference to tracking handle is only possible if the handle is stored on the stack. It cannot work if the passed List<> reference is stored in a field of an object on the heap, the garbage collector can move it and make the pointer invalid. The compiler will catch it and generate an error. The ^ is already a reference, no additional reference is needed.
Without the reference, the const keyword doesn't make a lot of sense anymore either. Not that it ever did before, the CLR cannot enforce it. Not that this mattered much here, this code could not be called from any other .NET language. They won't generate a pointer to the tracking handle.
Just fix it, there's little point in keeping bad code like this:
void foo(IList<int>^ list ) { ... }
Example of code that shows that the reference cannot work:
using namespace System;
using namespace System::Collections::Generic;
ref class Test {
public:
IList<int>^ lst;
void foo(IList<int> const &list) {}
void wontcompile() {
foo(lst); // C3699
IList<int>^ okay;
foo(okay);
}
};
It's a reference which is constant to a tracking handle.
It allows you to pass the handle by reference instead of by value. Presumably the author thinks it's more efficient than copying the handle.
If the author meant to make the handle constant he should have used either of
Method(TestClass const ^ const & parameter)
Method(TestClass const^ parameter)
Or alternatively
Method(TestClass const^& parameter) - but the caller must const up the handle first
with
TestClass const^ constHandle = nonConstHandle
An example of each:
// test.cpp : Defines the entry point for the console application.
#include "stdafx.h"
ref class TestClass
{
public:
void setA(int value)
{
a = value;
}
TestClass() :
a(10)
{
}
private:
int a;
};
class TakesHandle
{
public:
void methodX1(TestClass const ^ const & parameter)
{
// Un-commenting below causes compiler error
// parameter->setA(11);
}
void methodX2(TestClass const^ parameter)
{
// Un-commenting below causes compiler error
// parameter->setA(11);
}
void methodX3(TestClass const^& parameter)
{
// Un-commenting below causes compiler error
// parameter->setA(11);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
TakesHandle takes;
TestClass ^ test1 = gcnew TestClass();
// compiles
takes.methodX1(test1);
// compiles
takes.methodX2(test1);
TestClass const ^ constHandle = test1;
takes.methodX3(constHandle);
return 0;
}