LNK2019 when referencing a member function (unresolved external symbol)

42 views Asked by At

I want to setup a QueueHandler that organizes function calls of an arbitrary class. In my case, I have a UDP interface that should not be overloaded. Thus, the I have a queue of function calls, so that a UDP request is sent only every N milliseconds (or seconds). When try to add functions to the queue, I get the LNK2019 error that there is an unresolved external symbol (as far as I understand this error, this means that there is a declared symbol, but it is not defined). However, to illustrate the problem, I broke it down to the basic principle that reproduces the error:

QueueHandler

/* =============== Header file QueueHandler.h ============================= */
#pragma once
#include <QThread>

#include <queue>
#include <functional>
#include <iostream>
#include <chrono>

class QueueHandler : public QThread
{
    Q_OBJECT
public:
    QueueHandler(QObject* parent=nullptr);
    ~QueueHandler() = default;

    void run() override;

    template<typename _Callable, typename... Args>
    void QueueFunction(_Callable&& __f, Args&&... args);

private:
    uint m_iSleepSec{ 2 };
    std::queue<std::function<void()>> funcs;
};

/* =============== implementation QueueHandler.cpp ============================= */
//#include "QueueHandler.h"

QueueHandler::QueueHandler(QObject* parent /*= nullptr*/)
{}

void QueueHandler::run()
{
    bool bRunning = true;
    while (bRunning)
    {
        if (!funcs.empty())
        {
            std::function<void()> func = funcs.front();
            funcs.pop();
            func();
        }
        else 
        {
            std::cout << "No command available.\n";
        }

        std::cout << "Sleep for " << m_iSleepSec << "seconds...";
        this->msleep(m_iSleepSec * 1000);
        std::cout << "... proceed processing. \n ";
    }
}

template<typename _Callable, typename... Args>
void QueueHandler::QueueFunction(_Callable&& __f, Args&&... args)
{
    std::function<void()> func = std::bind(std::forward<_Callable>(__f), std::forward<Args>(args)...);
    funcs.push(func);
}

Test class that filles the Queue:

/* Header file LpTest.h*/
/* =============== implementation LpTest.cpp ============================= */ 
#pragma once
#include "QueueHandler.h"

#include <QtCore>

#include <memory>

class LpTest : public QObject
{
    Q_OBJECT
public:
    LpTest();
    ~LpTest() = default;

    void fillQueue();
    void testFunction(int iIn);
    void ping();

signals:
    void resultReady(QVariant var);

private:
    std::unique_ptr<QueueHandler> m_pQueueHandler{};
};
/* =============== implementation LpTest.cpp ============================= */
//#include "LpTest.h"

LpTest::LpTest()
{
    m_pQueueHandler = std::make_unique<QueueHandler>(this);
}

void LpTest::fillQueue()
{
    m_pQueueHandler->QueueFunction(&LpTest::testFunction, 2);
}

void LpTest::testFunction(int iIn)
{
    std::cout << "testFunction: " << iIn << "\n";
}

void LpTest::ping()
{
    std::cout << "ping\n";
}

The Main.cpp looks just like:

#include <QtCore/QCoreApplication>
#include "LpTest.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    LpTest myLp{};
    myLp.fillQueue();

    return a.exec();
}

The error occurs when calling fillQueue() from the LpTest class. Btw, when the queue is defined within the LpTest class, everything works fine. But I want to put it into another class, so I might reuse the QueueHandler later on. The exact error is: error LNK2019: unresolved external symbol "public: void __cdecl QueueHandler::QueueFunction<void (__cdecl QueueHandler::*)(class QString),char const (&)[6]>(void (__cdecl QueueHandler::*&&)(class QString),char const (&)[6])" (??$QueueFunction@P8QueueHandler@@EAAXVQString@@@ZAEAY05$$CBD@QueueHandler@@QEAAX$$QEAP80@EAAXVQString@@@ZAEAY05$$CBD@Z) referenced in function "public: void __cdecl LpTest::fillQueue(void)" (?fillQueue@LpTest@@QEAAXXZ)

Thanks in advance!

I have red the error guide for LNK2019 by Microsoft, but could not adopt it to my problem, since I think, everything is defined where it should be. Microsoft Linker Tools Error LNK2019

1

There are 1 answers

1
Nils Mügge On

Problem solved. It is not allowed to define template functions in the cpp file. I have moved the definition of QueueFunction to the header file (ugly but that seems to be the way to go...)

Edit: additionally the QueueFuntion is slightly wrong. The std::bind needs to know the "caller" of the function. The correct implementation looks like:

template<typename Caller, typename _Callable, typename... Args>
QueueFunction(Caller* _caller, _Callable&& __f, Args&&... args) 
{
        std::function<void()> func = std::bind(std::forward<_Callable>(__f), _caller, std::forward<Args>(args)...);
...
}

and is corespondingly called with:

m_pQueueHandler->QueueFunction(this, &LpTest::firstFunction, 1);