forward declaration of template class not working with msvc but gcc

Hey guys,

I wrote a lib that needs to run under linux and windows.
In linux I'm compiling with GCC and in windows I'm using msvc2017.

In my library-header I have some forward declaration of classes.
I also have a forward-declaration of a template class like this:

1
2
3
4
5
6
7
8
9
template <class T>
class NDataObjectTx;

class NETLIBC_EXPORT netLibC
{

    template <typename T>
    bool getDataObject(NDataObjectTx<T> **dataObject);
...


In linux everything compiles without a problem but in windows I'm getting a linker-errors LNK2019 (unresolved external symbol) regarding this type.


Do you have any idea why this is happening?
Last edited on
themts (1)
Hey guys,

I wrote a lib that needs to run under linux and windows.
In linux I'm compiling with GCC and in windows I'm using msvc2017.

In my library-header I have some forward declaration of classes.
I also have a forward-declaration of a template class like this:

template <class T>
class NDataObjectTx;

class NETLIBC_EXPORT netLibC
{

template <typename T>
bool getDataObject(NDataObjectTx<T> **dataObject);
...


In linux everything compiles without a problem but in windows I'm getting a linker-errors LNK2019 (unresolved external symbol) regarding this type.


Do you have any idea why this is happening?


make it look exactly like the class, template bit and all, does that work?
which vs?
Last edited on
meanwhile I think it is not the forward declaration of that template class.
It is the implementation of that function.

In my .h file i have:
1
2
3
4
5
6
7
8
template <class T>
class NDataObjectTx;

class NETLIBC_EXPORT netLibC
{
...
template <typename T>
    bool getDataObject(NDataObjectRx<T> **dataObject);


im my .cpp file I have:
1
2
3
4
5
6
7
8
9
template<typename T>
bool netLibC::getDataObject(NDataObjectRx<T> **dataObject)
{
    ...
}
// and some explicit declarations
...
template bool netLibC::getDataObject(NDataObjectRx<unsigned short> **dataObject);
...


now I call that function like that:
1
2
NDataObjectRx<unsigned short> *dataObject;
m_netLibC.getDataObject(&dataObject);


With this linker error:
 
main.obj:-1: error: LNK2019: unresolved external symbol ""public: enum FRESULT __cdecl netLibC::getDataObject<unsigned short>(class NAhedDataObjectRx<unsigned short> * *)" 



I can compile and run the same code in linux and I'm not getting any error. In windows I cannot compile it.
I am surprised that works in Linux even.

Put all the template code in the header file.
Why?
As long as I explicitly instantiate each template-type it should normally be ok to put it in my cpp file
templates are supposed to be all in the header. Doing otherwise .. yea, you can often get it working (esp small programs), but it can also cause weird errors.
Does it work if you move it to the H file? That should, in < 5 min, tell you whether that is the issue or not...

this link sort of takes a crack at answering the mechanics as to the why.
https://www.bogotobogo.com/cplusplus/template_declaration_definition_header_implementation_file.php
Last edited on
As long as I explicitly instantiate each template-type it should normally be ok to put it in my cpp file

Yes, it should. Can you provide a minimal, complete codeset that demonstrates the problem?
@jonnin:
I cannot easily put my code into the header as this is the header I'm publishing with my lib.
I'm using PIMPL to keep my header completely clean.
> Yes it compiles when I put everything in my header but unfortunately this is not the solution I'm looking for.

@MikeyBoy:
I will prepare something and post it asap.
very simple two-liner:

main.cpp:
1
2
3
4
5
6
7
int main(int argc, char *argv[])
{
    NetLibC lib;
    NDataObjectTx<int> *dob;

    lib.addDataObject(&dob);
}


netLibC.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef NETLIBC_H
#define NETLIBC_H

template <class T>
class NDataObjectTx;

class __declspec(dllexport) NetLibC
{

public:
    template <typename T>
    bool addDataObject(NDataObjectTx<T> **dataObject);
};

#endif // NETLIBC_H 


netLĂ­bC.cpp
1
2
3
4
5
6
7
8
9
10
11
#include "netlibc.h"
#include <QDebug>

template<typename T>
bool NetLibC::addDataObject(NDataObjectTx<T> **dataObject)
{
    qDebug() << "FUNCTION CALLED" << dataObject;
    return true;
}
template bool NetLibC::addDataObject(NDataObjectTx<int> **dataObject);



> Maybe it's worth mentioning, that the lib it self is compiling without any problem.
> It's the the app, that uses this lib which gets the LNK-Error (main.cpp)
Last edited on
Can't reproduce your problem. The following worked fine from the Windows command line with both
g++ main.cpp netlibc.cpp
and
cl /EHsc main.cpp netlibc.cpp


main.cpp
1
2
3
4
5
6
7
8
9
#include "netlibc.h" // <=== I presume you included this?

int main(int argc, char *argv[])
{
    NetLibC lib;
    NDataObjectTx<int> *dob;

    lib.addDataObject(&dob);
}



netlibc.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef NETLIBC_H
#define NETLIBC_H

template <class T>
class NDataObjectTx;

class __declspec(dllexport) NetLibC
{

public:
    template <typename T>
    bool addDataObject(NDataObjectTx<T> **dataObject);
};

#endif // NETLIBC_H  



netlibc.cpp
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include "netlibc.h"

template<typename T>
bool NetLibC::addDataObject(NDataObjectTx<T> **dataObject)
{
    std::cout << "FUNCTION CALLED";
    return true;
}
template bool NetLibC::addDataObject(NDataObjectTx<int> **dataObject);


Insert this explicit instantiation declaration on line 14 in netlibc.h:

1
2
extern template __declspec(dllexport) 
bool NetLibC::addDataObject(NDataObjectTx<int> **dataObject);
Last edited on
Changed it like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef NETLIBC_H
#define NETLIBC_H

template <class T>
class NDataObjectTx;

class __declspec(dllexport) NetLibC
{

public:
    template <typename T>
    bool addDataObject(NDataObjectTx<T> **dataObject);
};
extern template __declspec(dllexport)
bool NetLibC::addDataObject(NDataObjectTx<int> **dataObject);

#endif // NETLIBC_H 


Unfortunately it has not helped to fix the problem.


main.obj:-1: error: LNK2019: unresolved external symbol ""public: bool __cdecl NetLibC::addDataObject<int>(class NDataObjectTx<int> * *)" (??$addDataObject@H@NetLibC@@QEAA_NPEAPEAV?$NDataObjectTx@H@@@Z)" in Funktion "main".


I can try to install mingw to see if it compiles then, but with MSVC 2017 it is not compiling.
Last edited on
> same result with minGW:


TestApp\main.cpp:20: error: undefined reference to `bool NetLibC::addDataObject<int>(NDataObjectTx<int>**)'
Unfortunately it has not helped to fix the problem.


Then we need to consider your build process. Given these three files:
netlibc.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef NETLIBC_H
#define NETLIBC_H

template <class T>
class NDataObjectTx;

class __declspec(dllexport) NetLibC
{

public:
    template <typename T>
    bool addDataObject(NDataObjectTx<T> **dataObject);
};

extern template __declspec(dllexport)
bool NetLibC::addDataObject(NDataObjectTx<int> **dataObject);

#endif // NETLIBC_H 


netlibc.cpp
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include "netlibc.h"

template<typename T>
bool NetLibC::addDataObject(NDataObjectTx<T> **dataObject)
{
    std::cout << "FUNCTION CALLED";
    return true;
}
template bool NetLibC::addDataObject(NDataObjectTx<int> **dataObject);


main.cpp
1
2
3
4
5
6
7
8
9
#include "netlibc.h" // <=== I presume you included this?

int main(int argc, char *argv[])
{
    NetLibC lib;
    NDataObjectTx<int> *dob;

    lib.addDataObject(&dob);
}


These commands produce a working executable:
D:\explicit_inst_decl>cl /nologo /EHsc /LD netlibc.cpp
netlibc.cpp
   Creating library netlibc.lib and object netlibc.exp

D:\explicit_inst_decl>cl /nologo /EHsc main.cpp netlibc.lib
main.cpp
   Creating library main.lib and object main.exp

D:\explicit_inst_decl>main.exe
FUNCTION CALLED
D:\explicit_inst_decl>
Last edited on
Or with MinGW
g++ -fPIC -Wl,--out-implib,netlibc.a -shared netlibc.cpp -o netlibc.dll
g++ main.cpp netlibc.a
I used the dependency-walker to check which functions were exported.
Unfortunately I don't see any of my template-functions.

I think I will simply overload all the different types and avoid templates in the dll-export.
Last edited on
Unfortunately I don't see any of my template-functions.
That's kind of the point of templates. They are not exported they are compiled into your program.
That's kind of the point of templates. They are not exported they are compiled into your program.

When a function template is instantiated, it produces a function, which can be exported:
D:\explicit_inst_decl>dumpbin netlibc.dll /EXPORTS /NOLOGO

Dump of file netlibc.dll

File Type: DLL

  Section contains the following exports for netlibc.dll

    00000000 characteristics
    FFFFFFFF time date stamp
        0.00 version
           1 ordinal base
           3 number of functions
           3 number of names

    ordinal hint RVA      name

          1    0 000019C0 ??$addDataObject@H@NetLibC@@QEAA_NPEAPEAV?$NDataObjectTx@H@@@Z
          2    1 000025E0 ??4NetLibC@@QEAAAEAV0@$$QEAV0@@Z
          3    2 000025E0 ??4NetLibC@@QEAAAEAV0@AEBV0@@Z

  Summary

        3000 .data
        3000 .pdata
       12000 .rdata
        1000 .reloc
       22000 .text
        1000 _RDATA

D:\explicit_inst_decl>
Topic archived. No new replies allowed.