Problem
This is hands down the strangest thing I've ever experienced. After 3 hours I managed to boil it down to this reproducible example (code below, sorry if it's a little messy, I tried my best)
I marked the line with a comment. Please not, that the aline above is not a problem. I also provide some other definitions for the Test struct. If I replace the one provided in the MWE, then it compiles flawlessly. Most notably, I can just assign weights[0]
to A
and then call A.applyFunction<float>(...)
. So what is it with g++, that it doesn't like my array element? I first thought, that it might be due to the templated size, and indeed, if I replace that with a fixed size, it compiles. However, then A=weights[0]
shouldn't work either. I'm really curious, what the explanation will be.
Error message
g++ -o test -c test.cpp -O0 -ggdb -DDEBUG -D__DEBUG -Wextra -Wshadow -Wconversion -Werror -Wall
test.cpp: In constructor ‘Test<sz>::Test()’:
test.cpp:79:43: error: expected primary-expression before ‘float’
79 | weights[0] = weights[0].applyFunction<float>(test);
| ^~~~~
test.cpp:79:43: error: expected ‘;’ before ‘float’
79 | weights[0] = weights[0].applyFunction<float>(test);
Compiler Info:
g++ --version g++ (Ubuntu 9-20190428-1ubuntu1~18.04.york0) 9.0.1 20190428 (prerelease) [gcc-9-branch revision 270630] Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Code
#include <algorithm>
#include <array>
#include <cstdio>
#include <functional>
#include <iostream>
#include <iterator>
#include <ostream>
#include <stdexcept>
namespace Math{
template<typename R>
struct Matrix{
private: unsigned short nRows, nCols;
public:
R* data;
Matrix<R>() : nRows(0), nCols(0){}
Matrix<R>(unsigned short nRows_, unsigned short nCols_) : Matrix<R>(nRows_, nCols_, R{}){
}
Matrix<R>(unsigned short nRows_, unsigned short nCols_, const R& val) : nRows(nRows_),nCols(nCols_){
data = new R[nRows * nCols];
for( unsigned short i = 0; i < nRows; ++i ){
for( unsigned short j = 0; j < nCols; ++j ){
data[i*nCols+j] = val;
}
}
}
Matrix<R>(unsigned short nCols_, unsigned short nRows_, R* vals) : nRows(nRows_), nCols(nCols_){
data = new R[nRows * nCols];
std::copy(vals, vals+nRows*nCols, data);
}
~Matrix<R>(){
delete[] data;
}
Matrix<R>(const Matrix<R>& m) : nRows(m.nRows), nCols(m.nCols){
data = new R[nRows * nCols];
data = m.data;
}
Matrix<R>& operator=(const Matrix<R>& m){
nRows = m.getNumRows();
nCols = m.getNumCols();
data = new R[nRows * nCols];
std::copy(m.data, m.data+nRows*nCols, data);
return *this;
}
template<typename S>
Matrix<S> applyFunction(std::function<S(R)> f){
Matrix<S> result(nCols, nRows);
for( unsigned short i = 0; i < nRows; ++i ){
for( unsigned short j = 0; j < nCols; ++j ){
result.data[i*nCols+j] = f(data[i*nCols+j]);
}
}
return result;
}
unsigned short getNumCols() const{
return nCols;
}
unsigned short getNumRows() const{
return nRows;
}
};
}
float test(float x){return x*x;}
using Math::Matrix;
template<unsigned short sz>
struct Test{
std::array<Matrix<float>, sz+1> weights;
Test(){
Matrix<float> A;
A = Matrix<float>(2, 2, 0.132f);
weights[0] = Matrix<float>(2, 2, 0.132f);
A = A.applyFunction<float>(test);
weights[0] = weights[0].applyFunction<float>(test); /* Line 79 */
}
};
int main(){
Test<2> t;
}
Test #2 (works)
template<unsigned short sz>
struct Test{
std::array<Matrix<float>, sz+1> weights;
Test(){
Matrix<float> A;
A = Matrix<float>(2, 2, 0.132f);
weights[0] = Matrix<float>(2, 2, 0.132f);
A = weights[0];
A = A.applyFunction<float>(test);
// weights[0] = weights[0].applyFunction<float>(test);
}
};
Test #3 (works)
template<unsigned short sz>
struct Test{
std::array<Matrix<float>, 3> weights;
Test(){
Matrix<float> A;
A = Matrix<float>(2, 2, 0.132f);
weights[0] = Matrix<float>(2, 2, 0.132f);
A = A.applyFunction<float>(test);
weights[0] = weights[0].applyFunction<float>(test);
}
};