Skip to content

shared generator expressions #2673

Closed
Closed

Description

@nodatapoints

I would like to wrap generator expressions in a function like in the following example.

inline auto build(int n) {
    auto x = xt::make_xshared(xt::arange(n));
    return x*x;
}

xt::xtensor<double, 1> array;
array = build(10);

Currently this gives an error

/usr/include/xtensor/xexpression.hpp:575:9: error:
    ‘class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int,
    std::array<long unsigned int, 1> >’ has no member named ‘linear_begin’
  575 |         XTENSOR_FORWARD_METHOD(linear_begin)

As far as I understand, this is currently only possible for xexpressions of evaluated expressions.
My current workarounds are:

  • Evaluating the generator. This sacrifices laziness.
  • Passing array by reference. This is not idiomatic and only works if the assignment results in a evaluation.

Activity

  1. tdegeus commented on Mar 31, 2023

    @tdegeus
    Member

    I think that what happens is that the return forces the evaluation of the expression. (It is a bit tricky to see from you error snippet)

  2. nodatapoints commented on Apr 7, 2023

    @nodatapoints
    Author

    For a minimum example I took the following code

    #include <xtensor/xtensor.hpp>
    
    inline auto build(int n) {
        auto x = xt::make_xshared(xt::arange(n));
        return x*x;
    }
    
    int main() {
        xt::xtensor<double, 1> array;
        array = build(10);
    }

    xtensor 0.24.6, xtl 0.7.5, GCC 12.2.1.
    This gave the following errors:

    In file included from /usr/include/xtensor/xaccumulator.hpp:18,
                     from /usr/include/xtensor/xmath.hpp:27,
                     from /usr/include/xtensor/xcontainer.hpp:25,
                     from /usr/include/xtensor/xtensor.hpp:20,
                     from test.cpp:1:
    /usr/include/xtensor/xexpression.hpp: In instantiation of ‘class xt::xshared_expression<xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> > >’:
    test.cpp:4:30:   required from here
    /usr/include/xtensor/xexpression.hpp:575:9: error: ‘class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_begin’
      575 |         XTENSOR_FORWARD_METHOD(linear_begin)
          |         ^
    /usr/include/xtensor/xexpression.hpp:576:9: error: ‘class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_end’
      576 |         XTENSOR_FORWARD_METHOD(linear_end)
          |         ^
    /usr/include/xtensor/xexpression.hpp:577:9: error: ‘const class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_begin’
      577 |         XTENSOR_FORWARD_CONST_METHOD(linear_begin)
          |         ^
    /usr/include/xtensor/xexpression.hpp:578:9: error: ‘const class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_end’
      578 |         XTENSOR_FORWARD_CONST_METHOD(linear_end)
          |         ^
    /usr/include/xtensor/xexpression.hpp:579:9: error: ‘const class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_cbegin’; did you mean ‘get_cbegin’?
      579 |         XTENSOR_FORWARD_CONST_METHOD(linear_cbegin)
          |         ^
    /usr/include/xtensor/xexpression.hpp:580:9: error: ‘const class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_cend’
      580 |         XTENSOR_FORWARD_CONST_METHOD(linear_cend)
          |         ^
    /usr/include/xtensor/xexpression.hpp:582:9: error: ‘class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_rbegin’
      582 |         XTENSOR_FORWARD_METHOD(linear_rbegin)
          |         ^
    /usr/include/xtensor/xexpression.hpp:583:9: error: ‘class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_rend’
      583 |         XTENSOR_FORWARD_METHOD(linear_rend)
          |         ^
    /usr/include/xtensor/xexpression.hpp:584:9: error: ‘const class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_rbegin’
      584 |         XTENSOR_FORWARD_CONST_METHOD(linear_rbegin)
          |         ^
    /usr/include/xtensor/xexpression.hpp:585:9: error: ‘const class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_rend’
      585 |         XTENSOR_FORWARD_CONST_METHOD(linear_rend)
          |         ^
    /usr/include/xtensor/xexpression.hpp:586:9: error: ‘const class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_crbegin’
      586 |         XTENSOR_FORWARD_CONST_METHOD(linear_crbegin)
          |         ^
    /usr/include/xtensor/xexpression.hpp:587:9: error: ‘const class xt::xgenerator<xt::detail::arange_generator<int, int, int>, int, std::array<long unsigned int, 1> >’ has no member named ‘linear_crend’
      587 |         XTENSOR_FORWARD_CONST_METHOD(linear_crend)
          |         ^
    
  3. EALePain commented on May 15, 2026

    @EALePain

    It appears this and the issue I ran into share the same underlying issue: #2916. From the bit of detective work I've done its an interface issue, the methods generated by the macros that are yelling in the above code need to be gracefully disabled for certain types.

    I found a solution but have yet to get to a point I can confirm it doesn't break outside my specific use case.

    #define XTENSOR_FORWARD_CONST_METHOD(name)                     \
        decltype(auto) name() const                                \
            requires( requires(const E& e){ e.name(); } )          \
        {                                                          \
            return m_ptr->name();                                  \
        }
    
    #define XTENSOR_FORWARD_METHOD(name)                  \
        decltype(auto) name()                             \
            requires( requires(E& e){ e.name(); } )       \
        {                                                 \
            return m_ptr->name();                         \
        }
  4. EALePain commented on May 30, 2026

    @EALePain

    Does the pull request #2918 also fix this issue?

  5. JohanMabille commented on Aug 28, 2026

    @JohanMabille
    Member

    Yes it should.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions