Repository: xtensor-stack/xtensor (language: python)

Issue:
Incorrect flat index of N x 1 arrays
Indexing a N x 1 array `a` with flat index will always reference to the first element `a[0,0]`:

```
xt::xarray<float> a = xt::zeros<float>({10, 1});
a(2) = 100;
std::cout << a << std::endl;
```

Actual result:
```
{{ 100.},
 {   0.},
 {   0.},
 {   0.},
 {   0.},
 {   0.},
 {   0.},
 {   0.},
 {   0.},
 {   0.}}
```

Expected result:
```
{{   0.},
 {   0.},
 { 100.},
 {   0.},
 {   0.},
 {   0.},
 {   0.},
 {   0.},
 {   0.},
 {   0.}}
```


Discussion / hints:
When you call the access operator with fewer arguments than the number of dimensions, `xtnesor` prepends these arguments with `0` values until it matches the number of dimensions (see [here](https://xtensor.readthedocs.io/en/latest/expression.html#accessing-elements) for more details).

Therefore, `a(2)` is equivalent to `a(0, 2)` here, which is undefined behavior in your case (since the shape is `(10, 1)`).

See #2316 for the discussion about adding a `flat` method.
https://xtensor.readthedocs.io/en/latest/numpy.html#slicing-and-indexing
The a.flat[4] part is misleading. Maybe we could add a link to the [Accessing elements](https://xtensor.readthedocs.io/en/latest/numpy.html#slicing-and-indexing) section.
Indeed, good catch!
I spotted this, and I think that what is written above and in [the docs](https://xtensor.readthedocs.io/en/latest/expression.html#accessing-elements) is wrong. 
```cpp
#include <xtensor.hpp>

int main()
{
    xt::xtensor<size_t,2> a = {{0,1,2}, {3,4,5}};
    std::cout << a(2) << std::endl;
    return 0;
}
```
asserts:
```
terminating with uncaught exception of type std::runtime_error: .../xtensor/xcontainer.hpp:434: check failed
	index 2 is out of bounds for axis 0 with size 2
```

Fix patch:
diff --git a/include/xtensor/xexception.hpp b/include/xtensor/xexception.hpp
index 3449704df..0cc29e7a3 100644
--- a/include/xtensor/xexception.hpp
+++ b/include/xtensor/xexception.hpp
@@ -150,28 +150,40 @@ namespace xt
         template <class S, std::size_t dim, class T, class... Args>
         inline void check_index_impl(const S& shape, T arg, Args... args)
         {
-            if (sizeof...(Args) + 1 > shape.size())
+            if (std::size_t(arg) >= std::size_t(shape[dim]) && shape[dim] != 1)
             {
-                check_index_impl<S, dim>(shape, args...);
-            }
-            else
-            {
-                if (std::size_t(arg) >= std::size_t(shape[dim]) && shape[dim] != 1)
-                {
-                    XTENSOR_THROW(std::out_of_range,
-                                  "index " + std::to_string(arg) + " is out of bounds for axis " +
-                                  std::to_string(dim) + " with size " + std::to_string(shape[dim]));
-                }
-                check_index_impl<S, dim + 1>(shape, args...);
+                XTENSOR_THROW(std::out_of_range,
+                              "index " + std::to_string(arg) + " is out of bounds for axis " +
+                              std::to_string(dim) + " with size " + std::to_string(shape[dim]));
             }
+            check_index_impl<S, dim + 1>(shape, args...);
         }
     }
 
-    template <class S, class... Args>
-    inline void check_index(const S& shape, Args... args)
+    template <class S>
+    inline void check_index(const S&)
+    {
+    }
+
+    template <class S, class Arg, class... Args>
+    inline void check_index(const S& shape, Arg arg, Args... args)
     {
-        using value_type = typename S::value_type;
-        detail::check_index_impl<S, 0>(shape, static_cast<value_type>(args)...);
+        constexpr std::size_t nargs = sizeof...(Args) + 1;
+        if (nargs == shape.size())
+        {
+            detail::check_index_impl<S, 0>(shape, arg, args...);
+        }
+        else if (nargs > shape.size())
+        {
+            // Too many arguments: drop the first
+            check_index(shape, args...);
+        }
+        else
+        {
+            // Too few arguments: ignore the beginning of the shape
+            auto it = shape.end() - nargs;
+            detail::check_index_impl<decltype(it), 0>(it, arg, args...);
+        }
     }
 
     template <class S, class It>


Test patch:
diff --git a/test/test_xview.cpp b/test/test_xview.cpp
index fba27e703..25e42405a 100644
--- a/test/test_xview.cpp
+++ b/test/test_xview.cpp
@@ -22,7 +22,6 @@
 #else
 #endif
 
-
 #include "xtensor/xarray.hpp"
 #include "xtensor/xbuilder.hpp"
 #include "xtensor/xfixed.hpp"
@@ -1034,7 +1033,6 @@ namespace xt
         xtensor<double, 3> exp_v1 = {{{9, 12}, {13, 16}}};
 
         EXPECT_EQ(v1, exp_v1);
-
         test_view_iter(v1, exp_v1);
 
         auto v2 = xt::view(a, keep(1), xt::all(), xt::range(0, xt::xnone(), 3));
@@ -1053,9 +1051,9 @@ namespace xt
         EXPECT_EQ(v4, exp_v4);
 
         v4(0, 0) = 123;
-        v4(1, 0) = 123;
+        v4(1, 0, 0) = 123;
         EXPECT_EQ(a(0, 0, 0), 123);
-        EXPECT_EQ(a(1, 0, 0), 123);
+        EXPECT_EQ(a(2, 0, 0), 123);
 
         v3(0, 2, 1) = 1000;
         EXPECT_EQ(a(1, 1, 3), 1000);
@@ -1113,9 +1111,9 @@ namespace xt
         EXPECT_EQ(v4, exp_v4);
 
         v4(0, 0) = 123;
-        v4(1, 0) = 123;
+        v4(1, 0, 0) = 123;
         EXPECT_EQ(a(0, 0, 0), 123);
-        EXPECT_EQ(a(1, 0, 0), 123);
+        EXPECT_EQ(a(2, 0, 0), 123);
 
         bool b = detail::is_strided_view<decltype(a), xkeep_slice<int>, int>::value;
         EXPECT_FALSE(b);