How to avoid infinite recursion in C++ class templates - c++

I have a matrix class with the size determined by template parameters.
template <unsigned cRows, unsigned cCols>
class Matrix {
...
};
My program uses matrices of a few sizes, typically 2x2, 3x3, and 4x4. By setting the matrix size with template parameters rather than run-time parameters allows the compiler to do a lot of inlining and optimization.
But now I need a member function that returns a new matrix that has one fewer row and one fewer column.
Matrix<cRows - 1, cCols - 1> Reduced(unsigned row, unsigned col) const { ... }
The idea is that that it will return a matrix with the specified row and column deleted. In practice, this will only ever be called with a matrix that has at least three rows and three columns, returning a 2x2 at the smallest.
The compiler doesn't see the lower bound, so it gets stuck in an infinite recursion trying to instantiate the templates with ever decreasing sizes. I tried putting two clues in the function itself that these smaller sizes cannot occur:
Matrix<cRows - 1, cCols - 1> Reduced(unsigned row, unsigned col) const {
static_assert(cRows > 1 && cCols > 1);
if (cRows <= 1 || cCols <= 1) throw std::domain_error();
Matrix<cRows - 1, cCols - 1> r;
// ... initialize r ...
return r;
}
Neither the static_assert nor the if-statement seems to be a strong enough clue to the compiler that a 0x0 matrix will never be generated. (Ironically, it does complain about the if-statement having a constant compile-time condition.)
Does anyone have any suggestions on how to avoid this compile-time infinite recursion?

You need to provide a specialization for a Matrix that has no rows or no columns.
E.g.
template<unsigned cRows>
class Matrix< cRows, 0 >
{
Matrix<cRows - 1, 0> Reduced() { return Matrix<cRows - 1, 0>(); }
};
template<unsigned cCols>
class Matrix< 0, cCols >
{
Matrix<0, cCols - 1> Reduced() { return Matrix<0, cCols - 1>(); }
};
template<>
class Matrix< 0, 0 >
{
Matrix<0, 0> Reduced() { return Matrix<0, 0>(); }
};
The issue you have is that attempting to instantiate the Matrix Reduced function with a particular set of template parameters always required instantiating the Matrix template for a different set of parameters (cRows - 1, cCols -1). This recursion has to be stopped somewhere. If you are only ever dealing with square matrices, then you can get away with fewer specializations.
Also, you can could stop the recursion with a completely empty class if you are never going to use, say, a 1x1 matrix, the result of reduce on a 2x2 matrix.
template<>
class Matrix< 1, 1 > {};

You can specify a template specializations for small values of cRows or cCols which does not include that method.

You seem a bit confused about compile time and run time behaviour, and I'm a bit confused by your code, but I think what you want is a specialisation of the template for the values, 0, 0, which terminates the recursion.
If you haven't already got it, I suggest reading
C++ Templates: The Complete Guide by Vandervoorde & Josuttis, which covers this sort of thing in detail.

You need to explicitly specify the behaviour for the case where you want the recursion to end. See this DDJ article for more details. Here is a simple example from the article:
template<int n>
class META_FACTORIAL
{
public:
enum{
RET = n * META_FACTORIAL<n-1>::RET
};
};
template<>
class META_FACTORIAL<0>
{
public:
enum{ RET = 1 };
};

Rather than specializing the entire class to terminate the recursion, another option might be to use boost::enable_if on the function to make it available only when the matrix size is above 2x2.

Related

Compile-Time Creation of Array of Templated Objects in High Level Synthesis

I'm trying to accomplish this with HLS, not with "normal" C++, so most libraries (STL, boost, etc.) won't work as they can't be synthesized (manual memory management is not allowed). I think this should be possible with template metaprogramming, but I'm a little stuck.
I want to create an array of shift registers, each with a variable depth. I have N inputs, and I want to create N shift registers, with depths 1 to N, where N is known at compile time. My shift register class basically looks like
template<int DEPTH>
class shift_register{
int registers[DEPTH];
...
};
I tried following this and adapting it: Programmatically create static arrays at compile time in C++ , however, the issue is with the last line. Each templated shift register is going to be a different type, and so can't be put together in an array. But I do need an array, as there wouldn't be a way to access each shift register.
Any help would be appreciated!
Just to clarify, my problem was the following: generate N shift_registers, templated from 1 to N, where N is a compile time constant.
For example, if I had N=4, I could easily write this as:
shift_register<1> sr1;
shift_register<2> sr2;
shift_register<3> sr3;
shift_register<4> sr4;
But this wouldn't be easy to change, if I wanted a different value for N in the future.
I ended up using the preprocessor and took the solution from here: How do I write a recursive for-loop "repeat" macro to generate C code with the CPP preprocessor?
I used the macros from that solution like this:
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define BODY(i) shift_register<i> CAT(sr,i)
REPEAT_ADD_ONE(BODY, N, 1);
And then something similar to that in order to access the shift registers, in a sort of array fashion.
This let me achieve the compile time generation that I was looking for, and get the array type access I needed.
Your question was somewhat difficult to understand but I'll do my best...
template <typename ... Args>
constexpr auto make_array(Args && ... pArgs)
{
using type = std::common_type_t<std::decay_t<Args>...>;
return std::array<type, sizeof...(Args)>{ (type)pArgs ... };
}
Then use it like this:
auto constexpr var_array_of_arrays = std::make_tuple
(
make_array(1, 2, 3, 3),
make_array(2, 3, 4),
make_array(1, 2, 3 ,4 ,3, 5)
);
To get the M'th element you access it like this, n has to actually be a compile-time constant:
std::get<M>(var_array_of_arrays);
To access the Nth element in the Mth array:
auto constexpr value = std::get<M>(var_array_of_arrays)[N]
An to improve the interface:
template <size_t M, size_t N, typename T >
constexpr decltype(auto) get_element(T && pInput)
{
return std::get<M>(std::forward<T>(pInput))[N];
}
Used like this:
auto constexpr element0_1 = get_element<0, 1>(var_array_of_arrays);
This will allow you to use an array of variable length arrays, or atleast something that behaves like that and is identical to that in memory.
A full example is here:
Online compiler
Whenever I hear "compile time number sequence" I think std::index_sequence
namespace detail {
template <typename>
struct shift_registers;
template <std::size_t ... Is> // 0, 1, ... N-1
struct shift_registers<std::index_sequence<Is...> > {
using type = std::tuple<shift_register<Is + 1>...>;
};
template <typename T>
using shift_registers_t = typename shift_registers<T>::type
}
template <std::size_t N>
using shift_registers = detail::shift_registers_t<std::make_index_sequence<N>>;

C++ Eigen: recursive functions accepting any matrix class

I want to have a recursive function
template <typename Derived>
void f(Eigen::MatrixBase<Derived>& m)
{
size_t blockRows = ...
size_t blockCols = ...
....
f(m.block(0, 0, blockRows, blockCols));
}
This unfortunately results in an infinite compile time recursion.
The first call would be to
f<Eigen::MatrixBase<Derived> >
The second would be to
f<Eigen::Block<Eigen::MatrixBase<Derived>, ... > >
The third call would be to
f<Eigen::Block<Eigen::Block<Eigen::MatrixBase<Derived>, ... >, ... > >
Every time a block of block is requested.
What is the best practice to implement recursive functions in Eigen, which still work on any Eigen matrix type?
I think, I should use some type, that still wraps the same piece of memory, but is not an expression template and it is evaluated.
You can cast your recursive block to an Eigen::Ref to avoid the infinite type instantiation:
Ref<MatrixXd> bl = m.block(0, 0, blockRows, blockCols);
f(bl);
To stay fully generic, you can replace MatrixXd by typename Derived::PlainObject.

Template argument calculations

(NOTE: Working on a GCC 4.6 with no C++0x flags, external restriction. I am also interested on what would happen with C++11 and/or more recent compilers)
I have a templated class for operating on matrices of fixed size:
template<size_t rows, size_t cols, class Type>
class MatrixFixed;
In that class, I have defined a "shift" operation that has the following aspect:
template<size_t rows, size_t cols, class Type>
template<size_t numRowsUp>
MatrixLogicalFixed<rows,cols,Type> MatrixLogicalFixed<rows,cols,Type>::shiftUp( const Type & filler ) const
{
if( (numRowsUp>=rows) )
{
return MatrixLogicalFixed<rows,cols,Type>(filler);
}
else
{
MatrixLogicalFixed<numRowsUp,cols,Type> temp(filler);
return this->getSubMatrix<rows-numRowsUp,cols>( numRowsUp, 0 )
.joinV( temp );
}
}
The idea is that, if the number of positions to shift is larger than the total number of rows, a matrix filled with the default value can be returned.
However, in those cases (numRowsUp >= rows) the compilation ends with an internal compiler error: in force_constant_size at gimplify.c:691 at the last code line .joinV( temp )
Matrix sizes during the process (my guess):
Returned value: (rows x cols) matrix
getSubMatrix<rows-numRowsUp,cols>( numRowsUp, 0 ): when numRowsUp>=rows, this will result in a huge number due to size_t underflow
joinV function tries to deduce the appropriate return size, but this is impossible.
This is joinV declaration):
template<size_t rows, size_t cols, class Type>
template<size_t rows2, size_t cols2>
MatrixLogicalFixed<rows+rows2,cols,Type> MatrixLogicalFixed<rows,cols,Type>::joinV(const MatrixLogicalFixed<rows2,cols2,Type> & B) const
Since the if condition is defined at compile time, this is a piece of code that will NEVER be reached in the problematic case. What I have tried so far:
Use template parameters in preprocessor #if --obviously wrong.
Look for any kind of preprocessor macro MIN or MAX that can do the trick.
Usual partial specialization doesn't look like a valid workaround, since there are infinite combinations of values... I am open to any kind of solution. I just want my class to compile :D
What's wrong with preprocessor MAX?
You can use MAX(0, rows-numRowsUp) as template argument. Or try this as template argument: (numRowsUp>=rows)? 0 : rows-numRowsUp. This way wrong template will never be instaniated.

Is strict template evaluation in principle impossible in C++?

I think I understand how templates are evaluated lazily in C++ e.g. a la recursive replacements and a final simplification of the expansion. This typically limits the recursion depth available. I wonder if with the features new in C++11 (e.g. variadic templates or template packs) or with some Boost it is possible to force strict template evaluation. Or is this in principle impossible in C++?
Consider for example a template which sums all integer values 0..n:
template <int n>
struct sumAll { enum { value = n + sumAll<n-1>::value }; };
template <>
struct sumAll<0> { enum { value = 0 }; };
#include <iostream>
int main() { std::cout << sumAll<10000>::value << std::endl; }
Here sumAll<10>::value would be expanded to
sumAll<10>::value = 10 + sumAll<9>::value
= 10 + 9 + sumAll<8>::value
= 10 + 9 + 8 + sumAll<7>::value
= ...
= 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
and the final summation would only be performed once the template has been completely expanded. If that final expansion gets too long (e.g. in complex series expansions with many terms) the compiler will ultimately run out of space to store additional terms.
My question was in essence if there was a way to perform simplifications (like above summation) earlier.
You decide the recursion depth yourself. And just like normal recursion can cause stack overflows, template recursion can. But that's often fixable by a better recursive algorithm. Trivially:
template <int n>
struct sumAll { enum { value = n + n-1 + sumAll<n-2>::value }; };
template <>
struct sumAll<1> { enum { value = 0 }; };
template <>
struct sumAll<0> { enum { value = 0 }; };
Smarter:
template <int n>
struct sumAll { enum { value = (n*n+2)/2; };
Of course, you may complain that the latter is just being silly and real examples are more complex. But isn't that the whole problem? The compiler can't magically make that complexity go away for you.
C++ templates are turing-complete, which means that you use them to evaluate every computable function at compile time. It then follows from the halting theorem that
You cannot, in general, compute the amount of memory require to compile of a C++ program in advance. (I.e., there is no computable function which maps every C++ program to a memory bound for its compilation)
You cannot, in general, decide whether the compiler will ever finish instantiating template, or will go on forever.
So while you might be able to tweak a compiler to use less memory in some cases, you cannot solve the general problem of it running out of memory sometimes.

Compile-time search in static-array

In a project, I have several classes which encapsulate, among other things, matrices implemented as static-arrays, e.g.:
struct StaticContainer
{
static const short e[2][4];
};
/// Initialize components of member-array (with external linkage).
const short StaticContainer::e[2][4] = {
{ -1, 0, 0, 1 },
{ 0, -1, 1, 0 }
};
I would like to implement a meta-function which provides the inverse-mapping, from a column in StaticContainer::e back to the second index (1-4 in this case). Ideally, something like this:
template< typename TContainer, short TeX, short TeY >
struct VectorToIndex
{
enum { value = ??? };
};
Finally, I would like to pass (if this is possible at all):
BOOST_STATIC_ASSERT( 0 == VectorToIndex< StaticContainer, -1, 0 >::value );
Is this possible at all? My initial attempts to recursively-search through the 'e'-matrix failed, because whenever I try to access (at compile-time) the entries within I get (GCC):
error: ‘StaticContainer::e’ cannot appear in a constant-expression
Shall I understand that the values in the matrix are not available at compile-time?
I would appreciate any comments. I am free to change the way the matrix is initialized/stored (so I was thinking of some compile-time registration mechanism). The only constraint is to get this inverse-mapping at compile-time.
Clarifications:
Each column in the e-matrix represents a spatial direction (in this case, 2D). The columns are guaranteed to be distinct.
I would expect the following results from the meta-function:
VectorToIndex< StaticContainer, -1, 0 > --> '0' at compile-time
VectorToIndex< StaticContainer, 0,-1 > --> '1' at compile-time
VectorToIndex< StaticContainer, 0, 1 > --> '2' at compile-time
VectorToIndex< StaticContainer, 1, 0 > --> '3' at compile-time
If this template is instantiated with an invalid combination of numbers (i.e. which is not a column in the matrix), I would like to produce a compilation-error.
The solution I currently have is a simple program which writes files with the necessary template-instantiations manually. This satisfies the requirements (results are correct and for invalid vectors there is a compile-time error - since the corresponding template-instantiation is missing). However, since I have many classes similar to 'StaticContainer' in my codebase (many of them with larger matrices), this process generates thousands of lines of code :(.
As promissed, here goes a solution. Rather than reinventing a whole metaprogramming library using variadic templates, I used this opportunity to try out boost mpl and it turns out to be pretty expressive. Using it, VectorToIndex would look like the following:
template<typename basis, typename axis>
struct VectorToIndex :
boost::mpl::if_<
boost::mpl::greater<boost::mpl::size<basis>, typename boost::mpl::find<basis, axis>::type::pos>,
typename boost::mpl::find<basis, axis>::type::pos,
boost::mpl::empty_base
>::type
{
};
If "axis" is present in "basis" then VectorToIndex<basis, axis>::value equals its index in the range [0, size-of-basis). If otherwise this is not true, than VectorToIndex<basis, axis>::value is not defined, thus accessing it may be used to produce compile-time errors or
selective instanciation through SFINAE.
To represent the axis one should use boost::mpl::vector, like shown below:
typedef boost::mpl::vector<boost::mpl::int_<1>, boost::mpl::int_<0>, boost::mpl::int_<0> > e1;
typedef boost::mpl::vector<boost::mpl::int_<0>, boost::mpl::int_<1>, boost::mpl::int_<0> > e2;
typedef boost::mpl::vector<boost::mpl::int_<0>, boost::mpl::int_<0>, boost::mpl::int_<1> > e3;
Considering the definitions above, one has
VectorToIndex<boost::mpl::vector<e1, e2, e3>, e1>::value -> 0
VectorToIndex<boost::mpl::vector<e1, e2, e3>, e2>::value -> 1
VectorToIndex<boost::mpl::vector<e1, e2, e3>, e3>::value -> 2
VectorToIndex<boost::mpl::vector<e1, e2>, e3>::value -> COMPILE-TIME ERROR
There is a mismatch in your declarations:
typename TContainer means that the template parameter is a type
StaticContainer::e is a value
It cannot match.
There are a few potential solutions I can think of, but the first question is obviously: why not build the reverse matrix manually and use assert to prove its correctness ? It is certainly simpler, and simple is beautiful.