I was able to get it to work in VS 2015 only through type casting.
This compiles:foo((int *)arr,10,10);
A c-style cast might as well be a reinterpret_cast. Unless you can get by with a simple static_cast I would be highly suspect of any such code. (And this ignores the other problems with passing the array dimensions separately)
I don't think OP is doing that necessarily. They're looking for a way to pass an array of unknown size to a function. A pointer along with a length or stride is perfectly workable and efficient (though makes the interface prone to mistakes).Unless you have a really good reason to avoid heap allocation, I would always recommend writing a wrapper around a single dimensional std::vector that provides a 2D interface.
Multidimensional array syntax is a nightmare in C and C++.
BTW, those mistakes are exactly the kind of thing lkmViper noted above that array_view is meant to fix, however I believe array_view only works on a single dimension -- I could be mistaken though.
array_view works on multi-dimensional arrays. It's even smart enough to deduce the dimensions for the array from the variable in op's code since the arrays are compile-time sized.