QT static library how to export template - qt

I have a helper class that needs a template definition and works fine locally.
Now I try to put it in a static libary and use it in another program.
But when I use it, the linker reports a non-existent symbol. Is it possible to export the template definition somehow?
core_global.h
#pragma once
#include <QtCore/qglobal.h>
#define CORE_EXPORT Q_DECL_EXPORT
helper.h
#pragma once
#include "core_global.h"
template <typename E>
class CORE_EXPORT Helper
{
public:
Helper();
E fromString(const QString& text);
QString toString(E value);
};
helper.cpp
#include "Helper.h"
template<typename E>
Helper<E>::Helper()
{
}
template<typename E>
E Helper<E>::fromString(const QString& text)
{
// do something
return {};
}
template<typename E>
QString Helper<E>::toString(E value)
{
//do something
return {};
}

Related

QT how to pass Enum to EnumHelper correctly

I have found a helper class for enums (EnumHelper) to convert enums to strings and strings to enums.
I want to use this class in another class (MyEnums) in which I define different enums and want to provide a ToString() and FromString() method for each enum type.
If I try to convert an enum from a third class (Test) I get an error message that I don't understand.
EnumHelper.h
#pragma once
#include <QMetaEnum>
template <typename E>
class EnumHelper
{
public:
EnumHelper();
QString toString(E value);
};
EnumHelper.cpp
#include "EnumHelper.h"
template<typename E>
EnumHelper<E>::EnumHelper()
{
}
template<typename E>
QString EnumHelper<E>::toString(E value)
{
const int retval = static_cast<int>(value);
return QString::fromUtf8(QMetaEnum::fromType<E>().valueToKey(retval));
}
MyEnums.h
#pragma once
#include <QObject>
#include "EnumHelper.h"
class ColorNameEnums
{
Q_GADGET
public:
enum Value {
White,
Grey,
LightGrey,
DarkerGrey,
DarkGrey,
Mint,
DarkMint,
Red,
DarkRed,
Black,
Blue
};
Q_ENUM(Value)
private:
explicit ColorNameEnums();
};
class MyEnums : QObject
{
public:
explicit MyEnums(QObject* parent = nullptr);
QString colorNameToString(ColorNameEnums value);
ColorNameEnums colorNameFromString(QString value);
private:
EnumHelper<ColorNameEnums> m_colorName;
};
MyEnums.cpp
#include "MyEnums.h"
MyEnums::MyEnums(QObject* parent)
{
}
QString MyEnums::colorNameToString(ColorNameEnums value) { return m_colorName.toString(value); }
ColorNameEnums MyEnums::colorNameFromString(QString value) { return m_colorName.fromString(value); }
Test.h
#pragma once
#include <QObject>
#include "MyEnums.h"
class Test : public QObject
{
Q_OBJECT
public:
explicit Test(QObject* parent = nullptr);
private:
MyEnums* m_enums = new MyEnums();
};
Test.cpp
#include "Test.h"
Test::Test(QObject* parent)
{
}
void Test::test()
{
auto xx = m_enums->colorNameToString(ColorNameEnums::White);
}
Error is:
For a conversion of ""ColorNameEnums::Value"" to""ColorNameEnums"" no suitable constructor is available.

QtRemoteObjects autogenerated replica header complaining about undefined vtable

Started using QtRO and generated files inherently complain about vtable:
#ifndef REP_REMOTEEXAMPLE_H
#define REP_REMOTEEXAMPLE_H
// This is an autogenerated file.
// Do not edit this file, any changes made will be lost the next time it is generated.
#include <QtCore/qobject.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qvariant.h>
#include <QtCore/qmetatype.h>
#include <QtRemoteObjects/qremoteobjectnode.h>
#include <QtRemoteObjects/qremoteobjectpendingcall.h>
#include <QtRemoteObjects/qremoteobjectreplica.h>
class remoteExampleReplica : public QRemoteObjectReplica
{
Q_OBJECT
Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "remoteExample")
Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_SIGNATURE, "5e40a606abdd95f709878d419edaa735fce25d0d")
public:
remoteExampleReplica() : QRemoteObjectReplica() { initialize(); }
static void registerMetatypes()
{
static bool initialized = false;
if (initialized)
return;
initialized = true;
}
private:
remoteExampleReplica(QRemoteObjectNode *node, const QString &name = QString())
: QRemoteObjectReplica(ConstructWithNode)
{
initializeNode(node, name);
}
void initialize() override
{
remoteExampleReplica::registerMetatypes();
QVariantList properties;
properties.reserve(0);
setProperties(properties);
}
public:
virtual ~remoteExampleReplica() {}
Q_SIGNALS:
void Close(QString a);
void Open(QString b);
public Q_SLOTS:
void onClosed()
{
static int __repc_index = remoteExampleReplica::staticMetaObject.indexOfSlot("onClosed()");
QVariantList __repc_args;
send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);
}
void onOpened()
{
static int __repc_index = remoteExampleReplica::staticMetaObject.indexOfSlot("onOpened()");
QVariantList __repc_args;
send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);
}
private:
friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode);
};
#if (QT_VERSION < QT_VERSION_CHECK(5, 5, 0))
#endif
QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
#endif // REP_REMOTEEXAMPLE_H
The issue points to the private constructor. I only included the replica header in my code without really using the remote object as a test run. I've read a lot about vtables how they work and when the linker complains about the vtable but in this case, with the private constructor, I'm not sure what the issue is. Am I missing an implementation of the remote object? Did I not generate the files correctly?
.rep:
class remoteExample
{
SIGNAL(Close(QString a));
SIGNAL(Open(QString b));
SLOT(onClosed());
SLOT(onOpened());
};

What is this error about?

ALL,
I'm using Anjuta to do my development.
I created a project for my main application, and then made 2 more: 1 for the static library (libdbinterface.a) and 1 for the dynamic library (libsqlite_lib.so).
Both those libraries contains one exported class each: libdbinterface.a - class Database, libsqlite_lib.so - public SQLiteDatabase : public Database.
Now I'm trying to link libdbinterface.a to libsqlite_lib.so.
So in Anjuta I added following to the "Linker Option" for the target libsqlite_lib.so:
-L/home/igor/dbhandler/Debug/dbinterface -ldbinterface
However, trying to compile I received following error from linker:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/../../../../x86_64-pc-linux-gnu/bin/ld: /home/igor/dbhandler/Debug/dbinterface/libdbinterface.a(database.o): relocation R_X86_64_32S against `_ZTV8Database' can not be used when making a shared object; recompile with -fPIC
I tried to recompile libsqlite_lib.so with -fPIC explicitely added to "C++ Options" of that project but that didn't solve it - I still receive the same error.
Unfortunately trying to Google on how to link .a and .so is not helpful.
Can someone sched some light on how to fix this error?
TIA.
[EDIT]
libsqlite_lib.so Makefile - https://bpaste.net/show/1495231e58cc
libdbinterface.a Makefile - https://bpaste.net/show/3a71c119d0fc
libdbinterface.a contains 2 files databse.h:
#ifndef DBMANAGER_DATABASE
#define DBMANAGER_DATABASE
class Field
{
public:
Field(const std::string &columnName, const std::string &columnType, const std::string &columnDefaultValue = "", const bool columnIsNull = false, const bool columnPK = false)
{
column_name = columnName;
column_type = columnType;
column_defaultValue = columnDefaultValue;
column_isNull = columnIsNull;
column_pk = columnPK;
}
private:
std::string column_name, column_type, column_defaultValue;
bool column_isNull, column_pk;
};
struct FKField
{
FKField(const std::string &table_name, const std::string &original_field, const std::string &referenced_field)
{
tableName = table_name;
originalField = original_field;
referencedField = referenced_field;
}
std::string tableName, originalField, referencedField;
};
class Table
{
public:
Table(const std::string &tableName, const std::vector<Field> &tableFields, const std::map<int,std::vector<FKField> > &foreignKeys)
{
table_name = tableName;
table_fields = tableFields;
foreign_keys = foreignKeys;
}
const std::string &GetTableName() { return table_name; }
std::map<int,std::vector<FKField> > &GetForeignKeyVector() { return foreign_keys; }
private:
std::string table_name;
std::vector<Field> table_fields;
std::map<int,std::vector<FKField> > foreign_keys;
};
#ifdef WIN32
class __declspec(dllexport) Database
#else
class Database
#endif
{
private:
struct Impl;
Impl *pimpl;
public:
Database();
virtual ~Database();
Impl &GetTableVector();
static void *operator new(std::size_t size);
static void operator delete(void *ptr, std::size_t size);
virtual int Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg);
virtual int GetTableListFromDb(std::string &) { return 0; }
};
#endif
and database.cpp:
#ifdef WIN32
#include <windows.h>
#endif
#include <map>
#include <vector>
#include <string>
#include <sqlext.h>
#include "database.h"
struct Database::Impl
{
std::vector<Table> m_tables;
};
Database::Database() : pimpl( new Impl )
{
}
Database::~Database()
{
delete pimpl;
}
void *Database::operator new(std::size_t size)
{
return ::operator new( size );
}
void Database::operator delete(void *ptr, std::size_t size)
{
return ::operator delete( ptr );
}
Database::Impl &Database::GetTableVector()
{
return *pimpl;
}
int Database::Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg)
{
selectedDSN = selectedDSN;
errorMsg = errorMsg;
return 0;
}
libsqlite_lib.so has also 2 files: database_sqlite.h
#ifndef DBMANAGER_SQLITE
#define DBMANAGER_SQLITE
#ifdef WIN32
class __declspec(dllexport) SQLiteDatabase : public Database
#else
class SQLiteDatabase : public Database
#endif
{
public:
SQLiteDatabase();
~SQLiteDatabase();
virtual int Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg);
virtual int GetTableListFromDb(std::vector<std::wstring> &errorMsg);
protected:
void GetErrorMessage(int code, std::wstring &errorMsg);
private:
sqlite3 *m_db;
};
#endif
and database_sqlite.cpp with the actual implementation.
[/EDIT]
Well, apparently the solution is to rebuild static library with "-fPIC", not the dynamic one.
Thank you for reading.

C++ method defined in .h called in .cpp is not recognized

I am trying to use a method called getName() that is defined in the addPlayer.h file below. The getname() method will be used in the constructor called Player. The error that I get is: 'getName' was not declared in this scope'. How can I fix it?
Thanks for helping.
The addPlayer.h file:
#include "../Source/Player.h"
class addPlayer : public QDialog
{
Q_OBJECT
public:
addPlayer(QWidget *parent = 0);
~addPlayer();
tp::Player* makePlayer();
void addPlayer();
QString getName() const;
inline QString addPlayer::getName() const
{
return (ui.name_lineEdit->text());
}
The addPlayer.cpp file:
#include "addPlayer.h"
#include <QMessageBox>
using namespace tp;
addPlayer::addPlayer(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
QObject::connect(ui.ok_pushButton, SIGNAL(clicked()), this,
SLOT(validatePlayer()));
QObject::connect(ui.dateNaissance_pushButton, SIGNAL(clicked()), this,
SLOT(getDate()));
}
addPlayer::~addPlayer()
{
}
Player* makePlayer()
{
return new Player(getName().toStdString());
}
The constructor is as follows:
class Player: public HumanBeing {
public:
//Constructor
Player(const std::string& p_name);
Player::Player(const std::string& p_name): m_name(p_name)
You haven't properly scoped your definition of makePlayer -- you need to prefix addPlayer:::
Player* addPlayer::makePlayer()
{
return new Player(getName().toStdString());
}

QMake moc files confused by namespaces

I have a file that looks like:
#ifndef ENGINE_PLATFORM_AREAEDITOR_H
#define ENGINE_PLATFORM_AREAEDITOR_H
#include <QWidget>
#include "../Widgets/QtSfmlWidget.h"
namespace Engine { namespace World { class Area; } }
//This tell's Qt's qmake to ignore the code between MOC_SKIP_BEGIN and MOC_SKIP_END
// MOC_SKIP_BEGIN
#include "Engine/World/Area.h"
// MOC_SKIP_END
namespace Ui {
class AreaEditor;
}
class AreaEditor : public QWidget
{
Q_OBJECT
public:
Engine::World::Area area;
public:
explicit AreaEditor(QWidget *parent = 0);
~AreaEditor();
//...stuff....
private slots:
void on_markerTextEdit_textChanged();
void onDrawAreaScreen(sf::RenderTarget &renderTarget);
void onDrawAreaResized(const WindowSize &windowSize);
private:
Ui::AreaEditor *ui;
//...stuff....
};
#endif //ENGINE_PLATFORM_AREAEDITOR_H
However, when Qt is generating the _moc file, it incorrectly thinks 'AreaEditor' is in the namespace 'Engine', which then causes the compile to fail.
Here's an example snippet of the moc file that QMake is generating:
______/---------<-< Wrong
V V
void Engine::AreaEditor::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
AreaEditor *_t = static_cast<AreaEditor *>(_o);
switch (_id) {
case 0: _t->on_markerTextEdit_textChanged(); break;
case 1: _t->onDrawAreaScreen((*reinterpret_cast< sf::RenderTarget(*)>(_a[1]))); break;
case 2: _t->onDrawAreaResized((*reinterpret_cast< const WindowSize(*)>(_a[1]))); break;
default: ;
}
}
}
Here's what it should be:
void AreaEditor::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
The header file "Engine/World/Area.h" has a class called 'Area' that is in a namespace 'Engine' (actually, it's in 'Engine::World::", two nested namespaces). It seems like this is confusing QMake in some way!
If I remove the #include, commenting it out, everything compiles fine (except I have to pre-declare 'Area', and then can only use it as a pointer or a reference in the class).
So I tried wrapping the #include in a "MOC_SKIP_BEGIN", which I can find seemingly archaic references to online, hoping QMake will skip that header. Nope, still fails to compile.
Is there a way I can get this to compile while still being able to include the header I want to include?
From the documentation:
http://qt-project.org/doc/qt-5.0/qtdoc/moc.html#command-line-options
You can explicitly tell the moc not to parse parts of a header file. moc defines the preprocessor symbol Q_MOC_RUN. Any code surrounded by
#ifndef Q_MOC_RUN
...
#endif
is skipped by the moc.

Resources