Diferentes errores de compilación y enlace para static y constexpr entre clang y gcc.
Tengo el siguiente código:
“`lang-cpp
// template_header.hpp
<h1>ifndef TEMPLATE<em>HEADER</em>HPP</h1>
<h1>define TEMPLATE<em>HEADER</em>HPP</h1>
namespace template_header
{
template <int dim1>
/<em>static</em>/ constexpr int dim2 = 0;
<pre><code>template <>
/*static*/ constexpr int dim2<2> = 3;
template <>
/*static*/ constexpr int dim2<3> = 5;
</code></pre>
}
<h1>endif</h1>
<code>
</code>lang-cpp
// lib1.cpp
<h1>include <array></h1>
<h1>include "template_header.hpp"</h1>
template <int dim1>
class lib1<em>class
{
public:
std::array< double, template</em>header::dim2<dim1> > ar1 = {0};
};
<code>
</code>lang-cpp
// lib2.cpp
<h1>include <array></h1>
<h1>include "template_header.hpp"</h1>
template <int dim1>
class lib1<em>class
{
public:
std::array< double, template</em>header::dim2<dim1> > ar1 = {0};
};
“`
Si compilo cualquiera de los archivos .cpp
con static
descomentado, GCC me da un error “explicit template specialization cannot have a a storage class”.
Si static
está comentado, puedo compilar ambos archivos .cpp
y luego enlazarlos juntos como una biblioteca compartida con g++ lib1.o lib2.o -shared -o shared_lib.so
.
Sin embargo, si compilo con static
comentado con clang, no tengo problemas durante la compilación, pero obtengo un error “multiple definition of template_header::dim2<2>'" durante el enlace.
Si descomentostatic
, entonces todo se compila y enlaza correctamente.
Estoy bastante confundido al respecto, en primer lugar porque esta respuesta indica que, dado que mis constexpr
ocurren en un ámbito de espacio de nombres, deberían ser automáticamentestatic
y por lo tanto no deberían suponer ningún problema para el enlazador incluso si static
está comentado.
Además, no entiendo por qué agregar static
antes cambiaría cómo GCC compila los archivos .cpp
, dado que debería ser implícitamente static.
Se agradece cualquier explicación de los errores y posibles soluciones.
Edit: Estoy usando C++14.
davy.ai
El problema parece derivar del hecho de que las variables
constexpr
en el ámbito de un espacio de nombres tienen enlace interno de forma predeterminada en C++14, lo que significa que solo son visibles dentro de la unidad de traducción en la que están definidas. Es por esto que al descomentarstatic
en el código funciona, ya que especifica explícitamente el enlace interno.Cuando se comenta
static
, las variables aún se asumen con enlace interno de forma predeterminada en clang, pero en GCC se asume que tienen enlace externo, lo que conduce al error del enlazador ya quedim2<2>
ydim2<3>
están definidas en ambas unidades de traducción.Para solucionar esto, puedes especificar de forma explícita el enlace interno para las variables
constexpr
utilizandostatic
o un espacio de nombres anónimo:O:
Ambas opciones deberían funcionar sin errores de compilador o enlazador.