I'm doing an exercise in Shader School in which I implement a function that returns the nth power of a matrix. Even when I pass constant parameter n into the following function:
mat2 matrixPower(highp mat2 m, const int n) {
if(n==0) {
return mat2(1.0);
} else {
mat2 result = m;
for(int i=1; i < n; ++i) {
result = result * m;
}
return result;
}
}
I get the following error:
Loop index cannot be compared with non-constant expression
How is this possible?
The keyword const indicates that n is not writable, but it is still a variable and not a constant!
n varies with the actual parameter to the formal parameter when the function was called.
Note in Appandix A of The OpenGL ES Shading Language 1.0 are listed possible limitations for OpenGL ES 2.0:
for loops are supported but with the following restrictions:
condition has the form
loop_index relational_operator constant_expression
where relational_operator is one of: > >= < <= == or !=
In Chapter 5.10 Constant Expressions of The OpenGL ES Shading Language 1.0 is clearly said, that a const function parameter is not a constant expression:
A constant expression is one of
a literal value (e.g., 5 or true)
a global or local variable qualified as const excluding function parameters
an expression formed by an operator on operands that are constant expressions, including getting
an element of a constant vector or a constant matrix, or a field of a constant structure
a constructor whose arguments are all constant expressions
a built-in function call whose arguments are all constant expressions, with the exception of the texture lookup functions.
A workaround would be to create a loop which is limited by a constant expression and to break out off the loop with a condition:
for (int i = 1; i < 10; ++i)
{
if ( i >= n )
break;
result = result * m;
}
Related
Novice here trying a different method to pass array-by-reference in C++.
For C++, geeksforgeeks (under title Template Approach (Reference to Array)) shows a way to pass array by reference in C++ by creating a template. I am trying it because it seems a way to not use pointers and still pass arrays of different sizes on every different function call.
Notice in the following code from geeksforgeeks, a template parameter is specified for the size of the array.
// CPP Program to demonstrate template approach
#include <iostream>
using namespace std;
template <size_t N> void print(int (&a)[N])
{
for (int e : a) {
cout << e << endl;
}
}
// Driver Code
int main()
{
int a[]{ 1, 2, 3, 4, 5 };
print(a);
}
I have tried to extend the logic for 2D arrays by making a a template as followed:
template <size_t r, size_t c>
float approach_mean(vector<int>& n, float (&a)[r][c], float m, float d) {
return 0;
}
class Solution {
public:
int minimumDeviation(vector<int>& nums) {
float m = accumulate(nums.begin(), nums.end(), 0) / nums.size();
float dev = 0, devp = 0;
long double s = 0;
float r[2][nums.size()];
for (int i0 = 0; i0 < nums.size(); ++i0) {
r[0][i0] = nums.at(i0);
r[1][i0] = m - nums.at(i0);
dev = dev + abs(m - nums.at(i0));
}
dev = dev / nums.size();
while (devp < dev) {
devp = dev;
dev = approach_mean(nums, r, m, dev);
break;
}
return devp;
}
// float approach_mean() {
// }
};
Upon running this code, I get an error
Line 21: Char 19: error: no matching function for call to 'approach_mean'
dev = approach_mean(nums, r, m, dev);
^~~~~~~~~~~~~~~
Line 2: Char 7: note: candidate template ignored: could not match 'float' against 'float'
float approach_mean(vector<int>& n, float (&a)[r][c], float m, float d) {
^
1 error generated.
I simply can't think of ways to solve this error. I understand that it is unable to match the return type for some reason even though they are the same.
The entire logic is a WIP for a solution to Problem 1675 on Leetcode which is about reducing the deviation in an array.
Here is a part of the description of the problem:
You are given an array nums of n positive integers.
You can perform two types of operations on any element of the array any number of times:
If the element is even, divide it by 2.
For example, if the array is [1,2,3,4], then you can do this operation on the last element, and the array will be [1,2,3,2].
If the element is odd, multiply it by 2.
For example, if the array is [1,2,3,4], then you can do this operation on the first element, and the array will be [2,2,3,4].
The deviation of the array is the maximum difference between any two elements in the array.
Return the minimum deviation the array can have after performing some number of operations.
The problem is that float r[2][nums.size()]; is not standard C++ as the size of an array must be a compile time constant.
But as nums.size() is not a constant expression so it cannot be used to specify the size of an array and moreover it cannot be used as a template nontype argument as a template nontype argument must be a compile time constant.
You can verify this by changing nums.size() with some constant expression in float r[2][nums.size()]; and you will find out that the mentioned error is gone.
//-----------------v------>nums.size() replaced with 5
float r[2][5];
Demo with no compile time error
What does it mean when an intrinsic type has the parenthesis operators with it.
e.g. int() or float()
Is it like a default constructor or does it have a different meaning for intrinsic types?
----edit----
To add more context:
In my school textbook for C++, I am on a chapter about Templates. A template being used for demonstration is a Table template (a 2D array). One of the functions for Table is a resize method to change the dimensions of the table and is also used in some constructors used for Table. The constructor in question and the resize method are:
template <typename T>
Table<T>::Table<T>(int m, int n)
{
mDataMatrix = 0;
mNumRows = 0;
mNumCols = 0;
resize(m, n, T());
}
and
template <typename T>
void Table<T>::resize(int m, int n, const T& value)
{
// Destroy the previous data.
destroy();
// Save dimensions.
mNumRows = m;
mNumCols = n;
// Allocate a row (array) of pointers.
mDataMatrix = new T*[mNumRows];
// Now, loop through each pointer in this row array.
for(int i = 0; i < mNumRows; ++i)
{
// And allocate a column (array) to build the table.
mDataMatrix[i] = new T[mNumCols];
// Now loop through each element in this row[i]
// and copy 'value' into it.
for(int j = 0; j < mNumCols; ++j)
mDataMatrix[i][j] = value;
}
}
In the constructor definition, resize's third argument is T() (and I assume T becomes whatever the specified type for the template is).
In the definition for resize, T() is used for the value argument to assign a default value to the elements in the table.
From some of the earlier answers, this is zero-initialization. I assume that means the value is 0 for each element in the table (or some equivalent of 0 if the type is a string, I guess). Is this correct?
That is value initialization.
e.g. auto x = int(); means int x = 0
In the example provided T() will create an object of type T and pass it as a parameter.
You could also write:
resize(m, n, T{});
Acutally, your code does something different than when you're declaring just a int or a float. It zero initialize the numbers.
example, those three lines are equivalent:
int a = int();
int a = int{};
int a{};
All those three are zero initialized.
The following example seems to be very easy and straightforward:
void ftest(size_t& arg)
{
std::cout << arg << '\n';
}
int main()
{
size_t max = 5;
for (auto i = 0; i < max; ++i)
ftest(i);
}
but it won't compile (at least using VS2013) because the i is deduced as int and not as size_t. And the question is -- what is the point of auto in such for-loops if it can't rely on the conditional field? Would it be too much hard and time consuming if a compile analyze the whole statement and give expected result instead of what we're having now?
Because the type of variable is determined when declared (from its initializer), it has nothing do with how it will be used. If necessary type conversion would be considered. The rule is same as variables declared with type specified explicitly, auto is just helping you to deduce the type, it's not special.
Try to consider about this:
auto max = 5u;
for (auto i = 0; i < max; ++i)
// ~~~~~~~~
// i should be unsigned int, or max should be int ?
BTW: You could use decltype if you want the type to be determined by the conditional field max:
for (decltype(max) i = 0; i < max; ++i)
Keyword auto has nothing do with the rest of for statement, neither it knows about it. If you say it should infer from max, you are saying delay the type deduction, which won't comply with the auto type-inference rules.
Additionally, what about this?
size_t max = 5;
short min = 1;
for (auto i = 0; i < max && i > min; ++i)
Should it infer to short or size_t ? You cannot make compiler to read your mind!
Also, such delayed inference rules (if any) would complicate templates meta-programming.
You are actually providing a very simple case, where the condition is a simple i < max where the type of max is known. The standard tries to provide rules that apply in all cases, now let's consider this:
bool f(int);
bool f(size_t);
for (auto i = 0; f(i); ++i) { }
If the type of i was dependent on the conditional expression in the for loop, your compiler will probably not be happy.
Also, Herb Sutter as a small post on its blog about this issue actually: https://herbsutter.com/2015/01/14/reader-qa-auto-and-for-loop-index-variables/
I'm relatively new to C++. I just read about the auto keyword in regards to type deduction. I've tried implementing this in a couple functions only to find that it was causing all of kinds of issues when working with math operators. I believe what was happening was that my functions started implementing integer division when I actually needed float division (variables 'i' and 'avg'). I posted the code using the auto keywords below.
Now when I explicitly declared the variables as floats, the function worked fine.
So is this an example in which using auto would not be preferred? However, I can definitely see that they would help when generating the iterators.
namespace Probability
{
/* ExpectedValueDataSet - Calculates the expected value of a data set */
template <typename T, std::size_t N>
double ExpectedValueDataSet(const std::array<T, N>& data)
{
auto i = 0;
auto avg = 0;
for(auto it = data.begin(); it != data.end(); it++)
{
i = it - data.begin() + 1;
avg = ((i-1)/i)*avg + (*it)/i;
}
std::cout << avg << " \n";
return avg;
}
};
The literal 0 is of type int.
A variable auto avg = 0; therefore has type int.
The literal 0.0 (or e.g. 3.14) has type double, which is what you want.
As a general rule, use auto for a variable declaration where
the type is explicitly specified in the initializer, or
the type is awfully verbose, like some iterator type.
But don't use it without reason. :)
If for e.g. aesthetic reasons you want to keep i as an integer, then rewrite the computation
((i-1)/i)*avg + (*it)/i
to e.g.
((i-1)*avg + *it)/i
to avoid pure integer arithmetic for (i-1)/i.
I'm writing a small library for quantum mechanics and I want to use expression template to form operator expressions. Especially forming the Hamiltonian with expression template.
I basically followed this source to construct the code and overloading the corresponding operators + * -: https://en.wikipedia.org/wiki/Expression_templates
Forming the expression for the Hamiltonian requires a sum
Vec x = u_1 + u_2 + ... + u_N
where N is a (const) integer and u_i are also of type Vec. Writing this expression in the code works but I would like to be able to write
Vec x = Sum_{i=0}^{N} u_i
How would one do this?
------------ EDIT ------------
After some research and with the help of the comments, I came up with an idea of static for loop... After googling I found an article in http://www.drdobbs.com/loops-metaloops-c/184401835?pgno=8 which is exactly what I needed.
There is no way to write a template or function that magically pattern matches variables from the surrounding scope, so your u_i syntax can not work. You could do something similar with a macro, e.g.:
#define SUM_4(x) x ## 1 + x ## 2 + x ## 3 + x ## 4
Usage:
Vec u_1, u_2, u_3, u_4;
...
Vec x = SUM_4(u_);
You'd need to define additional macros for other numbers of source vectors.
The subscript operator in C++ is modeled by array access, e.g. u[1], u[2], .... If you are willing to maintain an array of Vec, you could write a generic function that iterates over the array. In this case the parameter would be the array. Something like:
template<typename T, int N>
T sum(T (&u)[N])
{
// (or your preferred summation procedure)
T x = u[0];
for (int i=1; i < N; ++i)
x += u[i];
return x;
}
Usage:
Vec u[4];
...
Vec x = sum(u);
Even better use a std::vector or fixed size array template.
P.S. Consider using Eigen.
EDIT: Updated sum() template with array size deduction from http://www.cplusplus.com/articles/D4SGz8AR/