Template argument calculations - c++

(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.

Related

How to enumerate a constant array at compile time in C++?

I am trying to generate a hash at COMPILE TIME from a literal string (array of characters). For example:
unsigned long long compiledHash = ComputeHash("literal string");
I am currently stuck on finding a way to enumerate all characters in the string and creating a unique hash. If I use a for loop like I would normally, the compiler won't generate the hash at compile time, which is not what I want.
I might of found a way to do so, but the compiler is stuck in an infinite loop when calculating the hash.
template <size_t _length, typename T, int n> struct CostructHash {
unsigned long long Value;
constexpr __forceinline CostructHash(const T(&str)[_length]) :
Value(str[n] ^ n + (n > 0 ? CostructHash<_length, T, n - 1>(str).Value : 0)) {}
};
template<size_t _length>
constexpr __forceinline unsigned long long ComputeHash(const char(&str)[_length]) {
return CostructHash<_length, char, _length - 1>(str).Value;
}
As you can see I use recursion to go through all characters in the string, but I must of messed up somewhere, because as I said the compiler freezes forever when it calls ComputeHash.
I understand that I must be missing the base case that stops the recursion, but as far as I understand (n > 0 ? CostructHash<_length, T, n - 1>(str).Value : 0) should do the job since I am always decreasing n by 1 and checking if n is bigger than 0. So why is the recursion not stopping?
Also, there may be an easier way to do what I am trying?
Do you see the problem in the code
The recursion is infinite because there is no base case for the template instantiations.
but as far as I understand (n > 0 ? CostructHash<_length, T, n - 1>(str).Value : 0) should do the job since I am always decreasing n by 1 and checking if n is bigger than 0. So why is the recursion not stopping?
The template is instantiated before the compiler decides whether that branch will be taken. You have to use if constexpr instead of the ternary conditional, or you have to specialise the template for the base case.
Also, there may be an easier way to do what I am trying?
This seems to work fine:
constexpr std::size_t
ComputeHash(std::string_view str) {
std::size_t result = 0;
std::size_t i = 0;
for(auto c : str) {
result += c ^ i++;
}
return result;
}

Eigen: function signature which accepts general matrix expression of fixed size and type

The Eigen documentation is filled with examples illustrating how one should write a general function accepting a matrix:
template <typename Derived>
void print_cond(const MatrixBase<Derived>& a)
The reason to use MatrixBase as opposed to Matrix is that all dense Eigen matrix expressions derive from MatrixBase. So, for instance, if I pass a block of a matrix
print_cond ( A.block(...));
Then using the signature const MatrixBase<Derived>& a avoids creating a temporary. Conversely, if we had declared the function with the signature
template <typename T, int rows, int cols>
void print_cond(const Matrix<T,rows,cols>& a)
then Eigen would have to convert the block type to a matrix before passing it to the function, meaning that an unnecessary temporary would have to be created.
Please correct me if this understanding is incorrect...
With that in mind, one of the benefits of the second approach is that we can get compile time checks on the dimensions of the matrix (assuming they are fixed, not dynamic).
What I can't find in the documentation is an example with the generality of the first approach (which helps avoid temporary creation), but which has complie time checks on the type and dimensions of the matrix. Could somebody please tell me how to do that?
Just for completeness, Marc and ggael are suggesting something like this
#include <iostream>
#include "Eigen/Dense"
using namespace Eigen;
using T = double;
const int rows = 5;
const int cols = 3;
template<typename Derived>
void print_cond(const MatrixBase <Derived> &a) {
/* We want to enforce the shape of the input at compile-time */
static_assert(rows == Derived::RowsAtCompileTime);
static_assert(cols == Derived::ColsAtCompileTime);
/* Now that we are guaranteed that we have the
* correct dimensions, we can do something... */
std::cout << a;
}
int main() {
print_cond(Matrix<T, rows, cols>::Ones());
/* These will not compile */
// print_cond(Matrix<T, rows + 1, cols>::Ones());
// print_cond(Matrix<T, rows, cols + 1>::Ones());
// print_cond(Matrix<T, rows + 1, cols + 1>::Ones());
return 0;
}

A compilation issue regarding constexpr expressions in Visual Studio 2017

I'm working on a rendering engine using Vulkan and Visual Studio 2017, and I bumped into the following type of problem recently.
I have a template struct template<uint32_t id> struct A;. This struct is defined (in separate header files) for id=0, ... , N-1. All of the definitions have a static constexpr std::array<B, M(id)> member for some struct B and number M depending on id. I have a constexpr function (and a helper function) which for a given value b of type B counts how many elements of all of these arrays equal to b. It looks something like this:
Helper function:
template<size_t Size>
constexpr void count_in_array(B b, const std::array<B, Size>& a, uint32_t& count)
{
for(auto& e : a)
{
if(e==b)
++count;
}
}
Main function:
template<uint32_t... ids>
constexpr uint32_t count_in_arrays(B b, std::index_sequence<ids...>)
{
uint32_t count=0;
auto l ={ (count_in_array(b, A<ids>::member, count), 0)... };
return count;
}
When I compile, I get a C1001 internal compiler error. The strange thing is that my funcions work, because if I use them to define a constexpr variable
constexpr uint32_t var=count_in_arrays(b, std::make_index_sequence<N>());
(for a constexpr B b),
and I hoover the mouse over that variable, I see the computed (and correct) number in the appearing rectangle.
I am not familiar with compiler switches, I only tried to use #pragma optimize("", on/off) around the above functions, but that didn't help. Does somebody have an idea how to make Visual Studio to compile my code?
Remark: I am pretty sure that the struct B is not important here, in my case, it is a simple data struct containing some built-in variables.
First, an internal compiler error is always a compiler bug. Please report this to MSVC.
Second, this implementation is a bit odd. When you write constexpr functions you want to think in a more functionally-oriented way - input-only arguments, output-only results. count_in_array should surely just return a number:
template <size_t Size>
constexpr uint32_t count_in_array(B b, const std::array<B, Size>& a)
{
uint32_t count = 0;
for(auto& e : a)
{
if(e==b)
++count;
}
return count;
}
This is a more reasonable implementation - count returns a count. Not only that, but it composes really nicely. How do you get all the counts? You sum them:
template <size_t... Ids>
constexpr uint32_t count_in_arrays(B b, std::index_sequence<Ids...>)
{
return (count_in_array(b, A<Ids>::member) + ...);
}
Much clearer.
Note that, while I think fold-expressions don't quite work in MSVC yet (though might soon?), that in of itself is not a reason to implement this differently. It just means that you need to manually sum - not that count_in_array() shouldn't return a count.

Using variadic templates to create a 2D array with variable column width?

Is it possible to create a "sparse" variable-length 2D array using only variadic templates and std::array? By sparse, I mean that each row could have a variable amount of columns.
Ideally, I'd like to instantiate something like VariableLengthTable<int,2,4,3>() and have it create an array of arrays that would map to something like {{0,1}, {0,1,2,3}, {0,1,2}}. I've seen SO posts that deal with variadic templates to create multidimensional arrays, but they are all symmetrical.
Note that I'm limited to zero-cost abstractions (e.g. std::array) as I'm working with a very memory constricted application.
Yes, this should be possible in principle. Here's a bit to get you started:
template <class T, std::size_t... Dim>
using VariableLengthTable = std::tuple<std::array<T, Dim>...>;
This is a tuple of std::arrays, each with a length specified by one of the template arguments.
Note that because the length of a std::array is part of its type, the first dimension cannot be an array, since its members would need different types. However, std::tuple works nicely. As long as you're willing to use std::get<i> instead of [i], and restrict yourself to compile-time is, you should be good.
If a compile-time i is not enough, you have two options:
One, use VariableLengthTable as above and add a runtime-to-compiletime conversion. Conceptually, something like this switch:
T& get(std::size_t x, std::size_t y)
{
switch (x) {
case 0: return std::get<0>(varLenTable)[y];
case 1: return std::get<1>(varLenTable)[y];
case 2: return std::get<2>(varLenTable)[y];
// and so on
}
}
In reality, you'd probably need to compose this using recursion or inheritance to avoid a compile-time out-of-bounds access. Boost.Preprocessor might help with that.
Two, store all the data in one sequential buffer and index into it at runtime. Something like this:
template <class T, std::size_t... Dim>
class VariableLengthTable
{
static const std::array<std::size_t, sizeof...(Dim)> dims = {{ Dim... }};
static const std::array<std::size_t, sizeof...(Dim)> cumulDims = [](){
std::array<std::size_t, sizeof...(Dim)> result;
result[0] = 0;
for (std::size_t idx = 1; idx < sizeof...(Dim); ++idx) {
result[idx] = result[idx - 1] + dims[idx];
}
return result;
}();
std::array<T, cumulDims[sizeof...(Dim) - 1] + dims[sizeof...(Dim) - 1]> data;
public:
T& get(std::size_t x, std::size_t y)
{
return data[cumulDims[x] + y];
}
};
The code above is to show the principle, not guaranteed to compile as-is.

How to avoid infinite recursion in C++ class templates

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.