Sending float over QDBus - qt

We currently migrated from Qt 4.5.x to 4.7.3, and since then we get errors when trying to send floats over DBus ('float' not registered as DBus type).
For instance:
QVariantList getTemperatures()
{
QVariantList retVal;
retVal << getSensorValue(1) << getSensorValue(2);
return retVal;
}
getSensorValueis a method that returns a floatvalue.
Since a QVariant in version prior to 4.6 could only contain a double value, the return values were implicitly cast to a double, and a doublecan be sent along the DBus.
But, since version 4,6, a QVariant can contain a float; as a result, the DBus module complains that floats are not a known datatype - which is correct.
I tried to register the float datatype, and to implement the streaming operators:
qDBusRegisterMetaType<float>();
QDBusArgument &operator<<(QDBusArgument &argument, const float &myFloat)
{
return argument << static_cast<double>(myFloat);
}
const QDBusArgument &operator>>(const QDBusArgument &argument, float &myFloat)
{
double d;
argument >> d;
myFloat = static_cast<float>(d);
return argument
}
But, when I try to stream the double into the QDBusArgument(operator <<), I get an error that the float datatype is trying to override the double behavior.
This is also normal, because the underlying QDbus system already has streamed the datatype ('f') to the QDBusArgument, and then detects that a double is entering the stream.
And now my question: does anybody know how I could stream this float, without having to replace all float datatypes with doubles in the backend methods?

(I had created at first an answer where I suggested you to use beginStructure() and endStructure() in order to make QtDBus stop complaining but then I realized that it doesn't solve your problem: you probably don't want to pass your float as a "double in a structure" but simply as a double.)
When passing directly the float to the QDBusArgument it gets casted automatically into a double and there is no problem. But if you want to pass it through a QVariantList you have no other choice than casting it before putting it into the QVariantList.
However if you're not afraid by dirty solutions you can overload the insertion operator of QVariantList to let it do it for you:
// g++ -o main main.cpp -lQtCore -lQtDBus
#include <QtDBus/QDBusArgument>
QVariantList & operator<<(QVariantList & list, const float & f)
{
QVariant variant(static_cast<double>(f));
list << variant;
return list;
}
int main()
{
QDBusArgument test;
QVariantList list;
float f = 1.0;
list << f;
test << list; // doesn't trigger any error
return 0;
}

Related

Why JsonCpp library parsing string success, take the string when the program is crash?

I found that the use of JsonCpp library parsed json string A, can not be resolved, the strange thing is that the analysis of string B is resolved successfully, when I take the string content when the program crashes, which is why? How can I avoid the crash?(string A:"http://192.168.1.1";string B:"192.168.1.1";)
#include"include/json/json.h"
#include <iostream>
int main(int argc, char** argv)
{
//compile:g++ -o test json_value.cpp json_writer.cpp json_reader.cpp json_test.cpp -I./include
Json::Value root; // will contains the root value after parsing.
Json::Reader reader;
bool parsingSuccessful = reader.parse( "192.168.1.1", root );//http://192.168.1.1
if ( !parsingSuccessful )
{
// report to the user the failure and their locations in the document.
std::cout << "Failed to parse configuration\n"
<< reader.getFormattedErrorMessages();
return 0;
}
else
{
std::cout << "Successfully parse configuration" << endl;
}
// Get the value of the member of root named 'encoding', return 'UTF-8' if there is no
// such member.
std::string encoding = root.get("encoding", "UTF-8" ).asString();
// And you can write to a stream, using the StyledWriter automatically.
std::cout << "encoding:" <<encoding << endl;
return 0;
}
What JSON do you expect the strings to contain?
Remember that JSON.parse accepts a string containing a valid JSON value.
Neither of the strings you mention are valid JSON values ("192.168.1.1" and "http://192.168.1.1"), it could be that jsoncpp is accepting "192.168.1.1" as a number by ignoring the .1.1 part (if so this is a bug).
If you expect a string you should quote them twice (once for C++ and once for the JSON).
bool parsingSuccessful = reader.parse("\"http://192.168.1.1\"", root);
In this example the first (unescaped) double quotes (") tell C++ this is a string, then the escaped double quotes (\") lets jsoncpp to parse a string variable.
If your compiler supports raw string literals you can avoid escaping the quotes.
bool parsingSuccessful = reader.parse(R"("http://192.168.1.1")", root);
Another example:
bool parsingSuccessful = reader.parse(R("{"a": 42, "b": "hi"})", root);

QT container, with specified order and no repetitions

I need somthing similar to QSet, but I need the items to be saved on the order I inserted them
is there such thing?
I am not aware of anything like that out of the box in neither Qt nor STL. Boost has something like that I think but it is not that hard to do this yourself.
You could do a wrapper around QHash like this:
template<typename T>
class MySet : QHash<T, int>
{
public:
using QHash<T, int>::QHash;
QVector<T> values() //this 'hides' the base QHash::values() of QHash
{
QVector<T> vec(count());
for(auto it = cbegin(); it != end(); ++it)
{
vec[it.value()] = it.key();
}
return vec;
}
void insert(const T &value)
{
if(!contains(value))
{
insert(value, m_Data.count());
}
}
};
The usage is quite similar to QSet:
MySet<QString> set;
set.insert("1");
set.insert("2");
set.insert("3");
qDebug() << set.values();
And that prints the values in order. If you need more complete support like iterators also iterating in your desired order you would have to reimplement more functionality but the gist of it would be the same. After all QSet is internally QHash as well. Note that the above does not support removal without modification.
Maybe a QList or a QVector could help.
QList<QString> stringList;
//By the way, Qt provides QStringList as a typedef for QList<QString>
stringList.append("A");
stringList.append("B");
qDebug() << stringList.at(0); //A
qDebug() << stringList.at(1); //B

How to write to struct from a GUI

Using Qt, I'm trying to write to my struct via inputs from a gui.
my target.h file:
struct Target{
double heading;
double speed;
};
my cpp:
#include <target.h>
struct Target myship;
myship.heading = 0;
myship.speed = 0;
I am using a QDial for the heading as an example. I can write the value of the QDial to a text file, but I would like to take advantage of structs.
What I'd like to know is how do I access, so that I can write to, the struct in my mainwindow.cpp?
I see that I can access my Target structure in mainwindow.cpp like this:
Target.heading
But it won't find "myship". I would have thought that I could have done
myship.heading...
or
Target.myship.heading...
But neither is working. When I do Target.heading it gives me the error
expected unqualified-id before '.' token
My ultimate goal is to have my gui (QDial in this case) write to the struct, and then have my gui (QLabel) display what has been written. As mentioned before, I have the read/write working with a text file, but I'm currently only writing out a single value, which isn't going to meet my requirements.
I'm new to Qt and structs in general so my guess is I'm missing something pretty trivial, or my understanding is off completely.
The struct prefix that you've used in the definition of the myship variable is a C-ism. It doesn't belong in C++. You should define myship as:
Target myship;
Furthermore, since it's 2016, you should use everything C++11 has got to make your life easier. Initialization of non-static/non-const class/struct members is very helpful and avoids boilerplate at the point of use of the struct. Thus, prefer:
// target.h
#include <QtCore>
struct Target {
double heading = 0.0;
double speed = 0.0;
};
QDebug operator(QDebug dbg, const Target & target);
// target.cpp
#include "target.h"
QDebug operator(QDebug dbg, const Target & target) {
return dbg << target.heading << target.speed;
}
// main.cpp
#include "target.h"
#include <QtCore>
int main() {
Target ship;
qDebug() << ship;
}
Note that you should include your own headers as #include "header.h", not #include <header.h>. The latter is reserved for system headers.
Without Qt:
#include <iostream>
struct Target {
double heading = 0.0;
double speed = 0.0;
};
int main() {
Target ship;
std::cout << ship.heading << " " << ship.speed << std::endl;
}

How can i make a QList<QVector3D> unique

I have a QList consist of QVector3D. A QVector3D represents a vertex or a point. This List holds also all vertices of a STL-File. The problem is that a vertex exist multiple times in the list. In need a list of the unique vertices of a STL-File. How can i implement it with Qt 5.0.2?
QSet uses a hash-function for ensuring the uniqueness of the value (QMap uses operator <)
There is no qHash implementation for QVector3D in Qt.
You could implement your own one e.g. as in example:
//place anywhere in Qt-code
#include <QSet>
#include <QVector3D>
#include <QList>
uint qHash(const QVector3D &v)
{
return qHash( QString( "%1x%2x%3" ).arg(v.x()).arg(v.y()).arg(v.z()) ) ;
}
int foo()
{
QList<QVector3D> uvector3D_1;
QSet<QVector3D> uvector3D_2;
uvector3D_2 = QSet<QVector3D>::fromList(uvector3D_1);
return 0;
}
static int testFoo = foo();
Of cause it is not the fastest one, it relies on Qt's function qHash for QString. But I think it's good for demonstration.
QList<QVector3D> originalVector = ...;
then either:
QSet<QVector3D> noDublicatesSet = QSet<QVector3D>::fromList(originalVector);
or
QSet<QVector3D> noDublicatesSet = originalVector.toSet();
also you can add something like if you need QList back..
QList<QVector3D> destinationVector = QList<QVector3D>::fromSet(noDublicatesSet);
you also will need those things (sorry has them in my code for ages.. forgot that they are external).. you might want to change hash function:
#define ROTL10(x) (((x) << 10) | (((x) >> 22) & 0x000000ff))
#define ROTL20(x) (((x) << 20) | (((x) >> 12) & 0x0000ffff))
uint qHash(double data)
{
union U {
quint64 n;
double f;
};
U u;
u.f = data;
return u.f;
}
inline uint qHash(const QVector3D &v, uint seed)
{
return qHash(v.x()) ^ ROTL10(qHash(v.y())) ^ ROTL20(qHash(v.z()));
}
P.S. that's a code for Qt 5.0, actually to add missing qHash() for vectors, that's why they dont fit in QSet/QHash by default
Starting from Qt 5.14, you can use the new constructor:
template <typename InputIterator> QSet::QSet(InputIterator first, InputIterator last
Here is an example taken from the docs:
// For example, if you have code like
QStringList list;
QSet<QString> set = QSet<QString>::fromList(list);
// you can rewrite it as
QStringList list;
QSet<QString> set(list.begin(), list.end());

Storing local dynamic_pointer_cast<>() in outer scope

In the following piece of code, I'm retrieving a shared_ptr<A> from a function. I then dynamically cast the pointer to a deriving class and store it in a shared_ptr<B>. The original pointer is not a nullptr.
shared_ptr<B> storage = nullptr;
if (...)
{
shared_ptr<A> definition = getSharedPointer();
// Store the lambda
storage = dynamic_pointer_cast<B>(definition);
}
I would expect the dynamic_pointer_cast and storage to storage to increase the total reference count to 2. Then, when I leave the scope of the if-statement, storage's reference count should be one.
Yet, when I tried to call a method on storage, I get a EXC_BAD_ACCESS, implying I'm reading in a deleted pointer.
storage->foo(...)->bar(...);
Is my logic wrong? Is this a bug in clang (can't imagine)?
EDIT
I seem to have found the error, which has nothing to do with the pointers. The function bar() actually gave the problem. If anyone ever reads this: the above code is perfectly valid.
This example works fine:
#include <memory>
using namespace std;
struct A {
virtual ~A() {}
};
struct B : A {};
shared_ptr<A> getSharedPointer() {
return make_shared<B>();
}
#include <iostream>
int main() {
shared_ptr<B> storage = nullptr;
if (true)
{
shared_ptr<A> definition = getSharedPointer();
// Store the lambda
storage = dynamic_pointer_cast<B>(definition);
}
cout << storage.get() << endl;
}
It would seem that your shared_ptr<A> is not pointing to a B and the result of the dynamic_pointer_cast is nullptr. Maybe a debugging statement would be helpful:
if (...)
{
shared_ptr<A> definition = getSharedPointer();
cerr << "as A: " << definition.get()
<< ", as B: " << dynamic_cast<B>(definition.get()) << endl;
// Store the lambda
storage = dynamic_pointer_cast<B>(definition);
}

Resources