Учитывая следующую программу:
#include <iostream>
#include "xtensor/xarray.hpp"#include "xtensor/xio.hpp"#include "xtensor/xview.hpp"xt::xarray<double> arr1
{1.0, 2.0, 3.0};
xt::xarray<double> arr2
{5.0, 6.0, 7.0};
template <typename T, typename U>
struct container{
container(const T& t, const U& u) : a(t), b(u) {}
T a;
U b;
};
template <typename T, typename U>
container<T, U> make_container(const T& t, const U& u){
return container<T,U>(t, u);
}
auto c = make_container(arr1, arr1);
std::cout << (arr1 * arr1) + arr2;
template <typename A, typename B, typename R>
auto operator+(const container<A, B>& e1, const R& e2){
return (e1.a * e1.b) + e2;
}
std::cout << (c + arr2);
Если мы посмотрим на код:
std::cout << (arr1 * arr1) + arr2;
Это выведет:
{ 6., 10., 16.}
Однако, запустив последнюю строку:
std::cout << (c + arr2);
Получает следующее:
{{ 6., 9., 14.}, { 7., 10., 15.}, { 8., 11., 16.}}
Почему это так? Я изменил определение функции operator+
к следующему:
template <typename A, typename B, typename R>
auto operator+(const container<A, B>& e1, const R& e2){
std::cout << __PRETTY_FUNCTION__ << std::endl;
return (e1.b * e1.alpha) + e2;
}
И результат был немного удивительным:
auto operator+(const container<A, B> &, const R &) [A = xt::xarray_container<xt::uvector<double, std::allocator<double> >, xt::layout_type::row_major, xt::svector<unsigned long, 4, std::allocator<unsigned long>, true>, xt::xtensor_expression_tag>, B = xt::xarray_container<xt::uvector<double, std::allocator<double> >, xt::layout_type::row_major, xt::svector<unsigned long, 4, std::allocator<unsigned long>, true>, xt::xtensor_expression_tag>, R = double]
auto operator+(const container<A, B> &, const R &) [A = xt::xarray_container<xt::uvector<double, std::allocator<double> >, xt::layout_type::row_major, xt::svector<unsigned long, 4, std::allocator<unsigned long>, true>, xt::xtensor_expression_tag>, B = xt::xarray_container<xt::uvector<double, std::allocator<double> >, xt::layout_type::row_major, xt::svector<unsigned long, 4, std::allocator<unsigned long>, true>, xt::xtensor_expression_tag>, R = double]
auto operator+(const container<A, B> &, const R &) [A = xt::xarray_container<xt::uvector<double, std::allocator<double> >, xt::layout_type::row_major, xt::svector<unsigned long, 4, std::allocator<unsigned long>, true>, xt::xtensor_expression_tag>, B = xt::xarray_container<xt::uvector<double, std::allocator<double> >, xt::layout_type::row_major, xt::svector<unsigned long, 4, std::allocator<unsigned long>, true>, xt::xtensor_expression_tag>, R = double]
{{ 6., 9., 14.}, { 7., 10., 15.}, { 8., 11., 16.}}
Почему там 3 +
операции, вызываемые в одной операции? Определен ли где-нибудь макрос, вызывающий такое поведение? R
введите в operator+
дает нам double
что на самом деле должно быть xt::xarray<double>
,
Любые идеи будут оценены, спасибо.
operator+
определяется в пространстве имен xt
принимает универсальные ссылки, и поэтому предпочтительнее вашей перегрузки, когда вы пишете c + arr2
,
Таким образом, эта последняя строка вернет xfunction
чей первый операнд твой container
и второй xarray
,
Теперь, так как container
это не xexpression
, внутри xfunction
это обрабатывается как … xscalar<container>
!
Таким образом, когда вы пытаетесь получить доступ к i-му элементу этого xfunction
выполняется следующая операция: xscalar<container> + arr2[i]
( xscalar
транслируется). поскольку xscalar<container>
конвертируется в container
, ваш operator+
перегрузка вызывается с R
решен как value_type
из arr2
, то есть, double
,
Следующий цикл иллюстрирует это поведение:
auto f = c + arr2;
for(auto iter = f.begin(); iter != f.end(); ++iter)
{
std::cout << *iter << std::endl;
}
Он генерирует следующие вызовы вашего operator+
:
operator+(c, arr[0]);
operator+(c, arr[1]);
operator+(c, arr[2]);
Вот почему вы видите 3 звонка вашего operator+
,
Других решений пока нет …