Search code examples
c++gcccompiler-errorsclangtemplate-specialization

Template and anonymous namespace Issue


So I am updating some C++11 code to use gcc-11, and have run into a issue...

Namely, it appears that in gcc-11 the constructor symbol, for a class, which is explicitly instantiated, does not exist if the constructor uses a type from a template class, defined in an anonymous namespace.

A simplified example that produces the issue can be seen below.

Clang-12 and gcc-8 do not exhibit this behavior and export the symbols (as I would have expected).

template.h:

#pragma once

namespace {
   template <typename T>
   struct MyAnonTempStruct
   {
      typedef float BaseType;
   };
}

template <typename T>
class MyTemplateClass
{
   public: 
   typedef typename MyAnonTempStruct<T>::BaseType BaseType;

   public: 
   MyTemplateClass(const BaseType* array);
};

template.cpp:

#include "template.h"

template <typename T>
MyTemplateClass<T>::MyTemplateClass(const BaseType* array)
{
}

template class MyTemplateClass<float>;

Using the compilation command

gcc -c -o template.o template.cpp

using nm I get the following symbol output for Clang-12 and gcc-8:

0000000000000000 W MyTemplateClass<float>::MyTemplateClass(float const*)
0000000000000000 W MyTemplateClass<float>::MyTemplateClass(float const*)
0000000000000000 n MyTemplateClass<float>::MyTemplateClass(float const*)

For gcc-11 I only get a text symbol:

0000000000000000 t MyTemplateClass<float>::MyTemplateClass(float const*)

If I mark the explicit specialization as extern in the header things work again in gcc-11. ie, adding:

extern template class MyTemplateClass<float>;

So I guess my question is: Is this expected behavior, and the fact that it previously worked was just because it was undefined, or is this some form of a miscompilation?


Solution

  • Anonymous namespaces generally should not be used in header files. There are very few exceptions to this, and your use case is not one. You can use a namespace detail to suggest to people that the code inside is not meant for them to use.

    GCC 11 is doing nothing wrong here, your code is simply not portable.