Undefined reference for ~queue with explicit template instantiation with Clang 10

Viewed 219

The following code doesn't link Clang 10 but succeed with GCC and Clang 9:

#include <queue>

template <typename T>
class A
{
public:
    void f();

private:
    std::queue<int> q;
};

template <typename T>
void A<T>::f()
{
    q = {};
}

template class A<int>;

int main()
{
    return 0;
}

What I get from the compiler is:

Online example

/opt/compiler-explorer/gcc-9.3.0/lib/gcc/x86_64-linux-gnu/9.3.0/../../../../x86_64-linux-gnu/bin/ld: /tmp/example-f70f65.o: in function `A<int>::f()':

/home/ce/<source>:16: undefined reference to `std::queue<int, std::deque<int, std::allocator<int> > >::~queue()'

clang-10: error: linker command failed with exit code 1 (use -v to see invocation)

Compiler returned: 1

It works if I replace std::queue with std::vector, std::deque or std::set; or if I remove the explicit template instantiation.

It also works if I remplace q = {} with the full constructor call q = std::queue<int>{}.

Is this code not standard or is it a compiler/libc++ bug?

1 Answers

I am not sure why you get such linker error, maybe its some unique issue with godbolt. If you try to compile your code with coliru : https://coliru.stacked-crooked.com/a/ac9c188334f858d8 you will get a compiliation time error indicating that you try to use list initialization of your queue:

main.cpp:16:7: error: no viable overloaded '='
    q = {};
    ~ ^ ~~
main.cpp:19:16: note: in instantiation of member function 'A<int>::f' requested here
template class A<int>;
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.5.0/../../../../include/c++/5.5.0/bits/stl_queue.h:96:11: note: candidate function (the implicit move assignment operator) not viable: cannot convert initializer list argument to 'std::queue<int, std::deque<int, std::allocator<int> > >'
    class queue
          ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.5.0/../../../../include/c++/5.5.0/bits/stl_queue.h:96:11: note: candidate function (the implicit copy assignment operator) not viable: cannot convert initializer list argument to 'const std::queue<int, std::deque<int, std::allocator<int> > >'
1 error generated.

queue does not allow list initialization with initializer_list, there is SO on this here: Why can't I construct a queue/stack with brace-enclosed initializer lists? (C++11)

But it appears you can make your code compile (at least on coliru, I tried on godbolt with no success) if you use libc++ (-stdlib=libc++) : https://coliru.stacked-crooked.com/a/df9d859a239843cf

It might not give exact answer to your question, but I it was too long for a comment. Also you might find similar thread here : https://github.com/envoyproxy/envoy/issues/9106

[edit] Interesting, after reseting godbolt UI and entering code again with the same configuration (https://godbolt.org/z/TzE9h9) everything works ok.

Related