QMetaType::Type from template type - c++

Is it possible to determine QMetaType::Type value of a template argument.
I tried this:
template <class T>
class MyClass {
public:
int getType() {
return QMetaType::type(typeid(T).name());
}
};
But this returns always 0 (QMetaType::UnknownType) because Qt uses different type names than the compiler.
It should work like the following:
MyClass<int>().getType(); // 2 (QMetaType::Int)
MyClass<QString>().getType(); // 10 (QMetaType::QString)
MyClass<QRect>().getType(); // 19 (QMetaType::QRect)
MyClass<MyType>().getType(); // 1024 (Set by qRegisterMetaType)

I tested your code on Qt 5.12.4 and it seems to work.
You could also Q_DECLARE_METATYPE to register your custom type and then use qMetaTypeId() to get the metaType id.
Here my test code and example:
#include <QCoreApplication>
#include <QDebug>
#include <QMetaType>
#include <QRect>
#include <QMetaObject>
class MyType
{
public:
int _member;
};
// needed for getType2()
Q_DECLARE_METATYPE(MyType);
// needed for getType()
const int id = qRegisterMetaType<MyType>("MyType");
template <class T>
class MyClass {
public:
int getType() {
return QMetaType::type(typeid(T).name());
}
int getType2() {
return qMetaTypeId<T>();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << MyClass<int>().getType();
qDebug() << MyClass<QString>().getType();
qDebug() << MyClass<QRect>().getType();
qDebug() << MyClass<MyType>().getType();
qDebug() << MyClass<int>().getType2();
qDebug() << MyClass<QString>().getType2();
qDebug() << MyClass<QRect>().getType2();
qDebug() << MyClass<MyType>().getType2();
return a.exec();
}
this outputs:
2
10
19
1024
2
10
19
1024

Related

invalid use of incomplete type with default template

I would like to create a C++ class with a default template parameter. However, I am having the following error:
error: invalid use of incomplete type
The code is the follow:
#include <iostream>
#include <string>
#include <array>
typedef std::array<double, 3> vec;
enum Op {Op1, Op2, Op3};
template<class T, enum Op S=Op1>
class classA
{
public:
class classInsideA
{
public:
classInsideA() {}
void tst()
{
std::cout << "inside A"<< std::endl;
}
};
void foo();
};
template<class T>
void classA<T>::foo() // not working
{
std::cout<< "I am being called in here" << std::endl;
}
int main(int argc, char** argv)
{
classA<vec> obj2;
return 0;
}
I would like that the default template would not change any of the current syntax in the class classA.
How can I fix this?
Edit:
Making the function have 2 template parameters, works.
template<class T, Op S>
void classA<T, S>::foo()
{
std::cout<< "I am being called in here" << std::endl;
}
But if the function has a default parameter, why do I need to specify the two templates. Shouldn't assume the default one?
Simply a typo I believe! You class has two template parameters and your function definition must also use both. See the full example below or here
typedef std::array<double, 3> vec;
enum Op {Op1=99, Op2, Op3};
template<class T, Op S=Op1>
class classA
{
public:
class classInsideA
{
public:
classInsideA() {}
void tst()
{
std::cout << "inside A we use Op value"<< S << std::endl;
}
};
classInsideA dummy;
void foo();
};
template<class T, Op S>
void classA<T, S>::foo() // not working
{
std::cout<< "I am being called in here and we use Op value" << S << std::endl;
}
int main(int argc, char** argv)
{
classA<vec> obj2;
obj2.dummy.tst();
obj2.foo();
return 0;
}

Constructor taking Base& is not called

I'm working on a simple program for Boolean algebra, but the double negation does not work as expected.
I have the following classes:
Operator:
#ifndef OPERATOR_H
#define OPERATOR_H
class Operator {
public:
virtual int getArity(void) const = 0;
virtual bool calc(void) const = 0;
};
#endif // OPERATOR_H
False:
#ifndef FALSE_H
#define FALSE_H
#include "operator.h"
class False : public Operator {
public:
int getArity() const {
return 0;
}
bool calc(void) const {
return false;
}
};
#endif // FALSE_H
Not:
#ifndef NOT_H
#define NOT_H
#include "operator.h"
class Not : public Operator {
public:
Not(Operator& child) : m_child(child) {
std::cout << "not constructor called" << std::endl;
}
int getArity(void) const {
return 1;
}
bool calc(void) const {
return !m_child.calc();
}
private:
Operator& m_child;
};
#endif // NOT_H
My main.cpp:
#include <iostream>
#include "operator.h"
#include "not.h"
#include "false.h"
using namespace std;
int main(int argc, char *argv[]) {
False f;
Not n = Not(f);
Not d = Not(n);
cout << "n.calc(): " << n.calc() <<endl;
cout << "d.calc(): " << d.calc() <<endl;
return 0;
}
Since d = Not(Not(False())) I expect it to be false.
The output is:
not constructor called
n.calc(): 1
d.calc(): 1 <== should be 0
Why is the constructor of the class Not not called with an object of type Not as child?
Not d = Not(n); invokes the copy constructor of Not, because the argument is also of type Not. The copy constructor's signature matches better and it's therefore selected.

Gmock can't mock a method that called in another method in the same class

I am investigating Gmock (Google Test Framework).
I run into an issue which I think Gmock can resolve it but It cannot. Please have a look to:
#include <iostream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using namespace std;
using ::testing::Invoke;
//---- THINGS TO TEST ---------
class MyTest {
public:
void display(const char* str);
void show_text();
};
void MyTest::display(const char* str){
cout << __func__<< " " << str << "\n";
cout << ":-->Inside the display myTest\n";
}
void MyTest::show_text(){
display("INSIDE MYTEST"); // HOW to mock display() here ?
}
//-------------------------------
//--- Configuration to test myTest ----
template <class myclass>
class Caller {
public:
myclass T;
void call_show_text() ;
void call_display(const char* s) ;
};
template <class myclass>
void Caller<myclass>::call_show_text()
{
T.show_text();
}
template <class myclass>
void Caller<myclass>::call_display(const char* str)
{
T.display(str);
}
void my_display(const char* str){
cout << __func__<< " OUTSIDE MYTEST\n" <<":-->Outside the display myTest\n";
}
struct MockTest {
MOCK_METHOD1(display, void(const char*));
MOCK_METHOD0(show_text, void());
};
//-------------------------------
//----- Test cases -------------
//----- Test cases -------------
TEST(TestShowTextMethod, CallDisplayOfmyTest){
Caller<MyTest> obj1;
obj1.call_show_text();
}
TEST(TestShowTextMethod, ReroutingDisplayToNewFunctionWithCallDisplay){
Caller<MockTest> obj2;
EXPECT_CALL(obj2.T, display("test_obj_2"))
.Times(1)
.WillOnce(Invoke(my_display));
obj2.call_display("test_obj_2");
}
TEST(TestShowTextMethod, ReroutingDisplayToNewFunctionWithCallShowText){
Caller<MockTest> obj3;
EXPECT_CALL(obj3.T, display("test_obj_3"))
.Times(1)
.WillOnce(Invoke(my_display));
obj3.call_display("test_obj_3");
}
TEST(TestShowTextMethod, ReroutingToNewFunctionWithCallShowText){
const char * str = "INSIDE MYTEST";
Caller<MockTest> obj4;
EXPECT_CALL(obj4.T, show_text());
EXPECT_CALL(obj4.T, display(str))
.Times(1)
.WillOnce(Invoke(my_display));
obj4.call_show_text();
}
//-------------------------------
//--- Initialization for test ----
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Only focus on the 4th test, I think Gmock can handle the fourth TEST: show_text calls display, why I can't mock display in this case ? Is Gmock impossible to mock a method is called in another method in the same class or I made a certain mistake in the 4th testcase ? I got a failed test-result like this:
../test_program.cpp:100: Failure
Actual function call count doesn't match EXPECT_CALL(obj4.T, display(str))...
Expected: to be called once
Actual: never called - unsatisfied and active
Of course, show_text and display() are exactly called.
Does anybody have an idea ?
why I can't mock display in this case?
You have not only successfully mocked display but also show_text as well. You should not lean on the behaviour of mocked implementation, because it will not be called.
Is Gmock impossible to mock a method is called in another method in the same class.
It is possible, but far from pretty, You can find example below. Note that there are some trade-offs made only for tests. Making DisplayController::display a virtual class is probably the biggest one.
class DisplayController
{
public:
virtual void display(const std::string& text)
{
cout << text << endl;
}
void show_str(const std::string& text)
{
cout << "Start" << endl;
display(text);
cout << "End" << endl;
}
};
class TestableDisplayController : public DisplayController
{
public:
MOCK_METHOD1(display, void(const std::string&));
MOCK_METHOD1(show_str_called, void(const std::string&));
void show_str(const std::string& text)
{
show_str_called(text);
DisplayController::show_str(text);
}
};
template <typename T>
class ClassUnderTest
{
public:
ClassUnderTest(T& display)
: displayController(display)
{}
void callDirectDisplay(const std::string& text)
{
displayController.display(text);
}
void callIndirectDisplay(const std::string& text)
{
displayController.show_str(text);
}
private:
T& displayController;
};
TEST(test, example)
{
TestableDisplayController mockedDisplayController;
ClassUnderTest<TestableDisplayController> sut(mockedDisplayController);
std::string l_directDisplay = "directDisplay";
std::string l_indirectDisplay = "indirectDisplay";
EXPECT_CALL(mockedDisplayController, display(l_directDisplay));
sut.callDirectDisplay(l_directDisplay);
EXPECT_CALL(mockedDisplayController, display(l_indirectDisplay));
EXPECT_CALL(mockedDisplayController, show_str_called(l_indirectDisplay));
sut.callIndirectDisplay(l_indirectDisplay);
}

Enum in constructor Qt C++

I'm create my own LOGGER, where I use an additional class for overload macro.
There is #define qlcd MacroCall(QLC::Debug), so i can use logger like this: qlcd << message;
It's ok, but when i try use qlcd("log name") i got an error. Look minimal code (no macro for simplify):
#include <QVariant>
#include <QDebug>
class QLC
{
public:
// Error types
enum LevelType{
Debug=0, // Debug
Error=1, // Error
WTF = 2 // WTF???
} level;
QString logger;
// Constructors
QLC(QLC::LevelType l)
:level(l), logger(":")
{}
QLC(QLC::LevelType l, QString log)
:level(l), logger(log)
{}
// OPERATOR <<
QLC& operator<<(const QVariant var){
qDebug() << "(" + QString::number(level) + ")" << logger << var;
}
};
class MacroCall
{
QLC::LevelType level;
public:
MacroCall()
:level(QLC::Debug){}
MacroCall(int i)
:level(QLC::WTF){}
MacroCall(QLC::LevelType l)
:level(l){}
QLC operator()(){
return QLC(level);
}
QLC operator()(QString log){
return QLC(level, log);
}
};
int main(int argc, char*argv[])
{
MacroCall()("WorkLog") << "No level, yes logname";
MacroCall(QLC::Error)() << "No logname, yes level";
MacroCall a(QLC::Error);
a("WorkLog") << "Logname and level at different lines";
// GET READY!
// INT as level and logname:
MacroCall(2)("WorkLog") << "WTF?? It works!";
//MacroCall(QLC::WTF)("NotWorkLog") << "It's not work!!!!!!";
// NOT WORK: error: invalid use of qualified-name 'QLC::WTF'
// Qt 4.8.3
return 0;
}
The code
MacroCall(QLC::WTF)("NotWorkLog")
is interpreted as declaration of a variable:
MacroCall QLC::WTF("NotWorkLog")
Example:
class A
{
public:
enum E {
x=1
};
public:
A(E) {}
void operator()(int) const { }
};
class B {};
void f()
{
(A(A::x))(1); // Ok
A{A::x}(1); // Ok
A(a)(A::x); // Ok
A::E a; // ‘a’ has a previous declaration as ‘A a’
A(A::x)(1); // invalid use of qualified-name ‘A::x’
B(b)(A::x); // no matching function for call to ‘B::B(A::E)’
}
The code you gave compiles (except that the method QLC& operator<<(const QVariant var) has to return something), eventhough I'm not sure of how it's supposed to be used.
My guess is that your 2 classes are defined in different headers and an include is missing. Does Macrocall header include QLC header ?

How to use c++ std complex numbers in QtScript

I try to find out how to use complex numbers in QtScripts such that slots defined with complex arguments can be called from a QtScript. Also basic algebra (+,-,exp, ... ) of complex-numbers should be accessible to the user from the script.
Just for illustration want I want to call is:
#include<complex>
typedef complex<double> Complex;
class MyCppClass : public QObject
{
Q_OBJECT
public:
...
public slots:
void mySignal(Complex rCValue); !! <<== should be callable from QtScript
...
}
Any ideas? Thx!
I think you must implement complex algebra in QtScript (something like http://examples.oreilly.com/9781565923928/text/8-6.txt) and then modify mySignal to accept an object like this.
It's not the final answer ... since as indicated above the operators +,- and * cannot be used for Complex quantities on the javascript side. But for those interested I'd like to share the following code pieces, which allow to trigger slots with complex arguments.
test.h:
#include <QtCore>
#include <QtScript>
#include <complex>
#include <iostream>
using namespace std;
typedef complex<double> Complex;
Q_DECLARE_METATYPE(Complex)
class TestClass : public QObject
{
Q_OBJECT
public:
TestClass() : QObject() {};
public slots:
void TestOutput(Complex rValue);
};
test.cpp:
#include "test.h"
void TestClass::TestOutput(Complex rValue)
{
cout << "received value "<< rValue << endl;
}
main.cpp:
#include "test.h"
QScriptValue toScriptValue(QScriptEngine *eng, const Complex& rValue)
{
QScriptValue obj = eng->newObject();
obj.setProperty("re",real(rValue));
obj.setProperty("im",imag(rValue));
return obj;
}
void fromScriptValue(const QScriptValue &obj, Complex& rValue)
{
double re=obj.property("re").toNumber();
double im=obj.property("im").toNumber();
rValue=Complex(re,im);
}
QScriptValue constructComplex(QScriptContext *context, QScriptEngine *engine)
{
Complex complex=Complex(2,1);
return engine->toScriptValue(complex);
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QScriptEngine eng;
// register our custom type
qScriptRegisterMetaType<Complex>(&eng, toScriptValue, fromScriptValue);
TestClass *test=new TestClass;
QObject *someObject = (QObject*)test;
QScriptValue objectValue = eng.newQObject(someObject);
eng.globalObject().setProperty("myObject", objectValue);
QScriptValue val = eng.evaluate("function Complex(real, imaginary) { this.re = real; this.im = imaginary;}; cadd = function (a, b) {return new Complex(a.re + b.re, a.im + b.im);};");
val = eng.evaluate("my_complex=new Complex(8,1); my_comp=new Complex(2,9); my_c=cadd(my_comp,my_complex);");
cout << "script"<< val.toString().toStdString() << endl;
Complex cval = qscriptvalue_cast<Complex>(val);
cout << "qscriptvalue_cast : "<< cval << endl;
val = eng.evaluate("myObject.TestOutput(my_c)");
return 0;
}