TransWikia.com

Instanciación explícita de plantillas extern: call of overloaded is ambiguous

Stack Overflow en español Asked on November 4, 2021

Estoy usando la librería armadillo para realizar cálculos con matrices, vectores, y otras yerbas.

Para acelerar los tiempos de compilación, estoy intentando compilar las instanciaciones en un único archivo, y declarar todas las plantillas como extern en los archvos .cpp en los que se usan:

// Un archivo.cpp
#include <armadillo>

extern template class arma::SpMat< arma::uword >;
extern template class arma::SpMat< arma::sword >;
...

Centralizando todas las instanciaciones usadas en un nuevo archivo:

// armadillo.cpp
#include <armadillo>

template class arma::SpMat< arma::uword >;
template class arma::SpMat< arma::sword >;
...

Pero, al intentar compilar el archivo armadillo.cpp:

In instantiation of ‘static void arma::arrayops::clean(eT*, arma::uword, eT, const typename arma::arma_not_cx::result*) [with eT = long long unsigned int; arma::uword = long long unsigned int; typename arma::arma_not_cx::result = long long unsigned int]’:

required from ‘const arma::SpMat& arma::SpMat::clean(typename arma::get_pod_type::result) [with eT = long long unsigned int; typename arma::get_pod_type::result = long long unsigned int]’

error: call of overloaded abs(long long unsigned int&) is ambiguous
val = (std::abs(val) <= abs_limit) ? eT(0) : val;

La protesta hace referencia a la primera instanciación, arma::uword. El trozo de código responsable es:

template<typename eT>
arma_hot
inline
void
arrayops::clean(eT* mem, const uword n_elem, const eT abs_limit, const typename arma_not_cx<eT>::result* junk)
  {
  arma_ignore(junk);
  
  for(uword i=0; i<n_elem; ++i)
    {
    eT& val = mem[i];
    
    val = (std::abs(val) <= abs_limit) ? eT(0) : val;
    }
  }

Por supuesto, antes de intentar esta centralización, todo compilaba y funcionaba correctamente.

Entiendo que la queja hace referencia a que varias posibles instanciaciones de std::abs( ) son susceptibles de compilar adecuadamente para el tipo arma::uword. Lo que me descoloca es que solo se queja al realizar instanciación explícita.

  • ¿ Hay alguna diferencia entre instanciación explícita e instanciación sobre-la-marcha ?

  • ¿ Que estoy haciendo mal ?

  • ¿ Como lo soluciono ?

One Answer

¿ Hay alguna diferencia entre instanciación explícita e instanciación sobre-la-marcha ?

Sí, en la instanciación explícita se compila absolutamente toda la plantilla, mientras que en la instanciación sobre la marcha solo se compilan aquellas funciones de la plantilla que se usan de manera efectiva.

Lo que está sucediendo es que la función arma::SpMat<arma::uword>::clean() no tiene uso en tu código y por eso no ha saltado ningún error, pero al forzar una implementación explícita la función se compila y ahí empiezan a aparecer los problemas.

¿ Que estoy haciendo mal ?

Lo que sucede es que std::abs no dispone de una implementación para los tipos sin signo... algo coherente ya que en los tipos sin signo el valor absoluto coincide siempre con el valor original.

¿ Como lo soluciono ?

Puedes crear una sobrecarga de std::abs para el tipo que te está dando problemas:

namespace std
{
  long long unsigned abs(long long unsigned value)
  { return value; }
}

No es la solución más elegante pero debería funcionar

Otra solución sería templatizar las llamadas problemáticas.

Nada te impide usar una plantilla que haga de interfaz entre tu código y la llamada a abs, por ejemplo:

template<class T>
struct StdCalls
{
  static T abs(T value)
  { return std::abs(value); }
}

template<>
struct StdCalls<long long unsigned>
{
  static long long unsigned abs(long long unsigned value)
  { return value; }
}

De esta forma evitas el error sin muchas complicaciones:

inline
void
arrayops::clean(eT* mem, const uword n_elem, const eT abs_limit, const typename arma_not_cx<eT>::result* junk)
{
  arma_ignore(junk);
  
  for(uword i=0; i<n_elem; ++i)
  {
    eT& val = mem[i];
    
    val = (StdCalls<eT>::abs(val) <= abs_limit) ? eT(0) : val;
    //     ~~~~~~~~~~~~~~~~~~~~~~
  }
}

Answered by eferion on November 4, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP