Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix "undefined symbol" in CLANG when using simple Template

I'm trying to implement a simple system using template struct, the code is very simple and compile fine with MSVC, yet i cannot understand why CLANG gives me this error: "lld-link : error : undefined symbol: public: static struct FMyStruct const TSpec<1>::m_struct"

I compile on a windows 64bitmachine with VisualStudio IDE but CLANG LLVM as compiler. The code works fine with MSVC. I simplified my problem to the very minimum, i tried to put everything in one single cpp file, with no result. I also tried explicit template instanciation. I want to be compliant with C++14, no C++17. One thing i tried that worked was declaring the m_struct member as an inline variable, but then i get this warning: "inline variables are a C++17 extension"

struct FMyStruct
{
    const int _p0;
    const int _p1;
    const int _p2;
};

template< int > struct TSpec {
    static constexpr FMyStruct m_struct = { 0, 0, 0 };
};

FMyStruct
Function( int i )
{
    return  TSpec< 1 >::m_struct;
}

int main()
{
    return 0;
}

Result:

"lld-link : error : undefined symbol: public: static struct FMyStruct const TSpec<1>::m_struct"

I expect the linker to find the symbol m_struct since it is defined very next to it ... The weirdest part is that if i try:

int
Function( int i )
{
    return  TSpec< 1 >::m_struct._p0;
}

the program will compile fine.

Edit: My CLANG version is 9.0.0, prebuilt distributed version for windows from the official website.

clang version 9.0.0 (trunk)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
like image 592
Layl Avatar asked Nov 07 '22 16:11

Layl


1 Answers

It indeed seems to be a bug related to the CLANG version, thanks @Sombrero Chicken for pointing this out.

So this is definitely weird but i managed to solve this avoiding the C++17-specific 'inline' declaration of the static member by adding this after the template struct definition:

template< int N > const FMyStruct TSpec< N >::m_struct;

By the way, it does not seem to be related to the template declaration at all. For summary, it gives this program that will compile fine.

struct FMyStruct
{
    const int _p0;
    const int _p1;
    const int _p2;
};

template< int > struct TSpec {
    static constexpr FMyStruct m_struct = { 0, 0, 0 };
};

template< int N > const FMyStruct TSpec< N >::m_struct;

FMyStruct
Function( int i )
{
    return  TSpec< 1 >::m_struct;
}

int main()
{
    return 0;
}

I still do not really understand why this is necessary since the static member is public to the struct, and part of the same unit & file; i guess this is a different matter but i'd like to be enlightened. Thank you.

like image 183
Layl Avatar answered Nov 14 '22 10:11

Layl