0

I don't use templates often, but I started working with Armadillo's library which has several different array and matrix types, and I wanted to write templates to cover versatile inputs instead of several functions with the same name.

I found this post that outlines a "trick" how to convert Armadillo's reference to arma::Mat object, and figured, for arrays it should be:

template <typename T>
const arma::Col<T>& as_Col(const arma::Col<T>& m) {return m;};
template<typename T1, typename eop_type>
arma::Col<typename T1::elem_type> as_Col(const arma::eOp<T1, eop_type>& X) {return {X};};

So I made simple check_array_size and save_data functions:

template <typename VectorA, typename VectorB> 
void check_array_size(const VectorA &A, const VectorB &B, const std::string &errorDescription)
{
    const auto& AA = as_Col(A);
    const auto& BB = as_Col(B);
    if (AA.n_elem != BB.n_elem)
        throw std::length_error(errorDescription);
}

and

template <typename VectorA, typename VectorB> 
void save_data(const VectorA &x, const VectorB &y, const std::string &fileName, const bool append)
{
    check_array_size(x,y,fileName);
    const auto& xx = as_Col(x);
    const auto& yy = as_Col(y);
    std::ofstream out_stream;
    if (append)
    {
        out_stream.open(fileName+".dat", std::ios_base::app);
        out_stream << "" << std::endl;
    }
    else
        out_stream.open(fileName+".dat");
    
    const uword N = yy.n_elem;
    for (uword i = 0; i < N; i++) 
        out_stream << xx.at(i) << " " << yy.at(i) << std::endl;
    out_stream.close();
}

The compiler did not want to finish installing this, it failed on a code line that was trying to use save_data with arguments arma::vec and arma::uvec:

 undefined reference to `void Nanosim::save_data<arma::Col<double>, arma::Col<unsigned long long> >(arma::Col<double> const&, arma::Col<unsigned long long> const&, std::string const&, bool)'

Now, I think I can solve this simply by removing calls to as_Col function and instantiating the template for save_data and check_array_size functions manually, for example:

template void save_data<arma::vec,arma::uvec>(const arma::vec&, const arma::uvec&, const std::string &, const bool);

but can someone please tell me what is going wrong, I have a hunch it's something simple, ie, wrong compiler, I am using C++17. I don't fully understand what as_Col function does, I simply want a neat way to write templates using Armadillo's matrix and array objects.

  • Did you perhaps but the definition of the function template in a `.cpp` file instead of putting it all in the header file? – Ted Lyngmo May 28 '23 at 20:54
  • Yup. I feel like an idiot. Haven't done templates in years. Moved the definition to .h. It's all working now. Thank you very much. – Aleksandar Demić May 28 '23 at 21:06

0 Answers0