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;
}
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