I am using the C++ library XTensor. I want to modify an array in-place in a function.
void modifyXArray(xt::xarray<double>& arr) {
arr += 1;
}
However when using this function:
auto tmp = xt::linspace(0, 1, 100);
modifyXArray(tmp);
I get the error:
/home/tom/src/xtensor-interp/tests/test_interpolator.cpp: In member function ‘virtual void Foo_Bar_Test::TestBody()’:
/home/tom/src/xtensor-interp/tests/test_interpolator.cpp:92:18: error: cannot bind non-const lvalue reference of type ‘xt::xarray<double>&’ {aka ‘xt::xarray_container<xt::uvector<double, std::allocator<double> >, xt::layout_type::row_major, xt::svector<long unsigned int, 4, std::allocator<long unsigned int>, true>, xt::xtensor_expression_tag>&’} to an rvalue of type ‘xt::xarray<double>’ {aka ‘xt::xarray_container<xt::uvector<double, std::allocator<double> >, xt::layout_type::row_major, xt::svector<long unsigned int, 4, std::allocator<long unsigned int>, true>, xt::xtensor_expression_tag>’}
92 | modifyXArray(tmp);
| ^~~
In file included from /home/tom/src/xtensor-interp/XTensorInterp/XTensorInterp/interpolator.h:11,
from /home/tom/src/xtensor-interp/tests/test_interpolator.cpp:1:
/home/tom/src/xtensor-interp/build/Release/_deps/xtensor-src/include/xtensor/xarray.hpp:501:12: note: after user-defined conversion: ‘xt::xarray_container<EC, L, SC, Tag>::xarray_container(const xt::xexpression<E>&) [with E = xt::xgenerator<xt::detail::arange_generator<double, int, double>, int, std::array<long unsigned int, 1> >; EC = xt::uvector<double, std::allocator<double> >; xt::layout_type L = xt::layout_type::row_major; SC = xt::svector<long unsigned int, 4, std::allocator<long unsigned int>, true>; Tag = xt::xtensor_expression_tag]’
501 | inline xarray_container<EC, L, SC, Tag>::xarray_container(const xexpression<E>& e)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/tom/src/xtensor-interp/tests/test_interpolator.cpp:85:39: note: initializing argument 1 of ‘void modifyXArray(xt::xarray<double>&)’
85 | void modifyXArray(xt::xarray<double>& arr) {
| ~~~~~~~~~~~~~~~~~~~~^~~
I can pass in an array by reference if I mark it as const, but then I cant modify it.
tmp
isn't an xt::xarray
it's a builder that can automatically be converted to an array. When you pass it to modifyXArray
it tries to do this conversion (see after user-defined conversion: ‘xt::xarray_container...
in the error message) but the conversion returns a temporary (rvalue) and you can't bind a temporary to a non-const reference (even if you did the temporary would be thrown away and your original variable wouldn't be modified). You need to force the conversion to an array before you pass to modifyXArray
, this is as simple as not using auto
:
xt::xarray<double> tmp = xt::linspace(0, 1, 100);
modifyXArray(tmp);
The conversion now happens when you construct tmp
and you now have a non-temporary array that you can pass to modifyXArray