es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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.

Tags:  , , , ,

Answer

  1. Avatar for 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 descomentar static 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 que dim2<2> y dim2<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 utilizando static o un espacio de nombres anónimo:

    // template_header.hpp
    #ifndef TEMPLATE_HEADER_HPP
    #define TEMPLATE_HEADER_HPP
    
    namespace template_header
    {
        template <int dim1="">
        static constexpr int dim2 = 0;
    
        template <>
        static constexpr int dim2<2> = 3;
        template <>
        static constexpr int dim2<3> = 5;
    }
    
    #endif
    

    O:

    // template_header.hpp
    #ifndef TEMPLATE_HEADER_HPP
    #define TEMPLATE_HEADER_HPP
    
    namespace
    {
        template <int dim1="">
        constexpr int dim2 = 0;
    
        template <>
        constexpr int dim2<2> = 3;
        template <>
        constexpr int dim2<3> = 5;
    }
    
    #endif
    

    Ambas opciones deberían funcionar sin errores de compilador o enlazador.

Comments are closed.