Search code examples
c++compiler-errorsc++17cluster-computingcompile-time

Compilation working on my Mac but not on the cluster (Linux)


I have a library in c++17 which compiles on my Mac, but not the cluster of my university (Linux).

My compiler is:

Apple clang version 11.0.0 (clang-1100.0.33.17)

The cluster compiler is:

g++ (Spack GCC) 9.2.0

Also a colleague of mine installed the library and compiled it with success on its machine (always a Mac).

I have tried to reduce everything to the main (I guess) error, putting everything in the code below.

Here is the error:

error: invalid use of incomplete type 'class TensorBase<double, std::integer_sequence<long unsigned int, 0> >'
  116 |  class Matrix<Real,1,1,NonZeroRow_>: public TensorBase<Real, std::make_index_sequence<1>>

Below I put the code. I basically have a BaseTensor class from which a class Matrix inherits. Of such a class I have also a specialisation.

#include <cstdlib>
#include <iostream>
#include <cassert>
#include <algorithm>
#include <numeric>
#include <array>  


    using Integer=long;
    using Real=double;



    template <typename T, std::size_t>
    using getTypeSequence = T;



    template <typename, typename>
    class TensorBase;

    template <typename T, Integer ... Is>
    class TensorBase<T, std::index_sequence<Is...>>
    {
    protected:
        std::array<T, sizeof...(Is)> values{};
        static const std::size_t Size = sizeof...(Is);

    public:
        constexpr TensorBase (getTypeSequence<T, Is> ... vals)
        : values{{vals...}}
        {}

        constexpr TensorBase (std::array<T, sizeof...(Is)> const & a)
        : values{a}
        {}

        constexpr TensorBase (std::array<T, sizeof...(Is)> && a)
        : values{std::move(a)}
        {}

        // TensorBase(std::initializer_list<T> a)
        // {
        //     assert(a.size() == Size);
        //     std::copy(std::begin(a), std::end(a), std::begin(values));
        // }
 
        constexpr TensorBase () = default;

        ~TensorBase() = default;

        constexpr TensorBase (TensorBase const &) = default;
        constexpr TensorBase (TensorBase &&) = default;

        constexpr TensorBase & operator= (TensorBase const &) = default;
        constexpr TensorBase & operator= (TensorBase &&) = default;
    };


    template<typename T, Integer Rows_, Integer Cols_,Integer NonZeroRow_=-1>
    class Matrix: public TensorBase<T, std::make_index_sequence<Rows_*Cols_>> 
    {
    public:
        static constexpr Integer Rows=Rows_;
        static constexpr Integer Cols=Cols_;
        using type= Matrix<T,Rows,Cols>;
        using subtype=T;
        using MB = TensorBase<T, std::make_index_sequence<Rows*Cols>>;
        using MB::MB;
        using MB::values;
        static constexpr Integer NonZeroRow=NonZeroRow_;
        inline constexpr static Integer rows() { return Rows; }
        inline constexpr static Integer cols() { return Cols; }
        inline constexpr std::array<T,Rows*Cols> &operator()()
        {
            return values;
        }

        inline constexpr const std::array<T,Rows*Cols> &operator()()const
        {
            return values;
        }
        // access matrix direclty by using I*Col+J index
        inline constexpr T &operator()(const Integer i)
        {
            assert(i < Rows*Cols);
            return values[i];
        }

        inline constexpr const T &operator()(const Integer i)const
        {
            assert(i < Rows*Cols);
            return values[i];
        }

        inline constexpr T &operator()(const Integer i, const Integer j)
        {
            assert(i < Rows);
            assert(j < Cols);
            return values[i*cols() + j];
        }

        inline constexpr const T &operator()(const Integer i, const Integer j) const
        {
            assert(i < Rows);
            assert(j < Cols);
            return values[i*cols() + j];
        }
    };





    template<Integer NonZeroRow_>
    class Matrix<Real,1,1,NonZeroRow_>: public TensorBase<Real, std::make_index_sequence<1>> 
    {
    public:
        static constexpr Integer Rows=1;
        static constexpr Integer Cols=1;
        using T= Real;
        using type= Matrix<T,Rows,Cols>;
        using subtype=T;
        using MB = TensorBase<T, std::make_index_sequence<Rows*Cols>>;
        using MB::MB;
        using MB::values;
        static constexpr Integer NonZeroRow=NonZeroRow_;
        inline constexpr static Integer rows() { return Rows; }
        inline constexpr static Integer cols() { return Cols; }

        inline constexpr std::array<T,Rows*Cols> &operator()()
        {
            return values;
        }

        inline constexpr const std::array<T,Rows*Cols> &operator()()const
        {
            return values;
        }

        inline constexpr T &operator[](const Integer i)
        {
            assert(i < Rows);
            return values[i];
        }

        inline constexpr T &operator[](const Integer i)const
        {
            assert(i < Rows);
            return values[i];
        }


        // access matrix direclty by using I*Col+J index
        inline constexpr T &operator()(const Integer i)
        {
            assert(i < Rows*Cols);
            return values[i];
        }

        inline constexpr const T &operator()(const Integer i)const
        {
            assert(i < Rows*Cols);
            return values[i];
        }

        inline constexpr T &operator()(const Integer i, const Integer j)
        {
            assert(i < Rows);
            assert(j < Cols);
            return values[i*cols() + j];
        }

        inline constexpr const T &operator()(const Integer i, const Integer j) const
        {
            assert(i < Rows);
            assert(j < Cols);
            return values[i*cols() + j];
        }


    };

    int main(int argc, char *argv[])
    {

        constexpr Matrix<Real,1,1> mat{1.0};


    std::cout<<"it works"<<std::endl;
    static_assert(mat(0,0)==1.0);



    return 0;
    }

Solution

  • using integer_sequence<Integer, Is...> instead of index_sequence<Is...> and adding const to the return of operator[] in Matrix<Real,1,1,NonZeroRow_> fixed the build error for me in gcc 10.1. I dont really know why using integer sequence instead fixes the problem, but besides fixing the build error the behavior should be equivalent in this case.

    here is the version that compiles after the edits that i made https://godbolt.org/z/dKHLDB

    #include <cstdlib>
    #include <iostream>
    #include <cassert>
    #include <algorithm>
    #include <numeric>
    #include <array>  
    
    
    using Integer=long;
    using Real=double;
    
    
    
    template <typename T, std::size_t>
    using getTypeSequence = T;
    
    
    
    template <typename, typename>
    class TensorBase;
    
    template <typename T, Integer ... Is>
    class TensorBase<T, std::integer_sequence<Integer, Is...>>
    {
    protected:
        std::array<T, sizeof...(Is)> values{};
        static const std::size_t Size = sizeof...(Is);
    
    public:
        constexpr TensorBase (getTypeSequence<T, Is> ... vals)
        : values{{vals...}}
        {}
    
        constexpr TensorBase (std::array<T, sizeof...(Is)> const & a)
        : values{a}
        {}
    
        constexpr TensorBase (std::array<T, sizeof...(Is)> && a)
        : values{std::move(a)}
        {}
    
        // TensorBase(std::initializer_list<T> a)
        // {
        //     assert(a.size() == Size);
        //     std::copy(std::begin(a), std::end(a), std::begin(values));
        // }
    
        constexpr TensorBase () = default;
    
        ~TensorBase() = default;
    
        constexpr TensorBase (TensorBase const &) = default;
        constexpr TensorBase (TensorBase &&) = default;
    
        constexpr TensorBase & operator= (TensorBase const &) = default;
        constexpr TensorBase & operator= (TensorBase &&) = default;
    };
    
    
    template<typename T, Integer Rows_, Integer Cols_,Integer NonZeroRow_=-1>
    class Matrix: public TensorBase<T, std::make_integer_sequence<Integer, Rows_*Cols_>> 
    {
    public:
        static constexpr Integer Rows=Rows_;
        static constexpr Integer Cols=Cols_;
        using type= Matrix<T,Rows,Cols>;
        using subtype=T;
        using MB = TensorBase<T, std::make_integer_sequence<Integer, Rows*Cols>>;
        using MB::MB;
        using MB::values;
        static constexpr Integer NonZeroRow=NonZeroRow_;
        inline constexpr static Integer rows() { return Rows; }
        inline constexpr static Integer cols() { return Cols; }
        inline constexpr std::array<T,Rows*Cols> &operator()()
        {
            return values;
        }
    
        inline constexpr const std::array<T,Rows*Cols> &operator()()const
        {
            return values;
        }
        // access matrix direclty by using I*Col+J index
        inline constexpr T &operator()(const Integer i)
        {
            assert(i < Rows*Cols);
            return values[i];
        }
    
        inline constexpr const T &operator()(const Integer i)const
        {
            assert(i < Rows*Cols);
            return values[i];
        }
    
        inline constexpr T &operator()(const Integer i, const Integer j)
        {
            assert(i < Rows);
            assert(j < Cols);
            return values[i*cols() + j];
        }
    
        inline constexpr const T &operator()(const Integer i, const Integer j) const
        {
            assert(i < Rows);
            assert(j < Cols);
            return values[i*cols() + j];
        }
    };
    
    
    
    
    
    template<Integer NonZeroRow_>
    class Matrix<Real,1,1,NonZeroRow_>: public TensorBase<Real, std::make_integer_sequence<Integer,1>> 
    {
    public:
        static constexpr Integer Rows=1;
        static constexpr Integer Cols=1;
        using T= Real;
        using type= Matrix<T,Rows,Cols>;
        using subtype=T;
        using MB = TensorBase<T, std::make_integer_sequence<Integer,Rows*Cols>>;
        using MB::MB;
        using MB::values;
        static constexpr Integer NonZeroRow=NonZeroRow_;
        inline constexpr static Integer rows() { return Rows; }
        inline constexpr static Integer cols() { return Cols; }
    
        inline constexpr std::array<T,Rows*Cols> &operator()()
        {
            return values;
        }
    
        inline constexpr const std::array<T,Rows*Cols> &operator()()const
        {
            return values;
        }
    
        inline constexpr T &operator[](const Integer i)
        {
            assert(i < Rows);
            return values[i];
        }
    
        inline constexpr const T &operator[](const Integer i)const
        {
            assert(i < Rows);
            return values[i];
        }
    
    
        // access matrix direclty by using I*Col+J index
        inline constexpr T &operator()(const Integer i)
        {
            assert(i < Rows*Cols);
            return values[i];
        }
    
        inline constexpr const T &operator()(const Integer i)const
        {
            assert(i < Rows*Cols);
            return values[i];
        }
    
        inline constexpr T &operator()(const Integer i, const Integer j)
        {
            assert(i < Rows);
            assert(j < Cols);
            return values[i*cols() + j];
        }
    
        inline constexpr const T &operator()(const Integer i, const Integer j) const
        {
            assert(i < Rows);
            assert(j < Cols);
            return values[i*cols() + j];
        }
    
    
    };
    
    int main(int argc, char *argv[])
    {
    constexpr Matrix<Real,1,1> mat{1.0};
    
    
    std::cout<<"it works"<<std::endl;
    static_assert(mat(0,0)==1.0);
    
    
    
    return 0;
    }
    

    here are the specific changes:

    before

    template <typename T, Integer ... Is>
    class TensorBase<T, std::index_sequence<Is...>>
    

    after

    template <typename T, Integer ... Is>
    class TensorBase<T, std::integer_sequence<Integer, Is...>>
    

    before

    template<typename T, Integer Rows_, Integer Cols_,Integer NonZeroRow_=-1>
    class Matrix: public TensorBase<T, std::make_index_sequence<Rows_*Cols_>> 
    

    after

    template<typename T, Integer Rows_, Integer Cols_,Integer NonZeroRow_=-1>
    class Matrix: public TensorBase<T, std::make_integer_sequence<Integer, Rows_*Cols_>> 
    

    before (in Matrix)

    using MB = TensorBase<T, std::make_index_sequence<Rows*Cols>>;
    

    after

    using MB = TensorBase<T, std::make_integer_sequence<Integer, Rows*Cols>>;
    

    before

    template<Integer NonZeroRow_>
    class Matrix<Real,1,1,NonZeroRow_>: public TensorBase<Real, std::make_index_sequence<1>> 
    

    after

    template<Integer NonZeroRow_>
    class Matrix<Real,1,1,NonZeroRow_>: public TensorBase<Real, std::make_integer_sequence<Integer, 1>> 
    

    before (in Matrix<Real,1,1,NonZeroRow_>)

    using MB = TensorBase<T, std::make_index_sequence<Rows*Cols>>;
    

    after

    using MB = TensorBase<T, std::make_integer_sequence<Integer, Rows*Cols>>;
    

    before (in Matrix<Real,1,1,NonZeroRow_>)

    inline constexpr T &operator()(const Integer i)const
    

    after

    inline constexpr const T &operator()(const Integer i)const