I don't know what's happening in this code.
SimpleFunction(1,2,3) is equal to
1&&(2&&3) //1
1||(2||3) //1
SimpleFunction(1) is equal to
1&&Something //1
1||Something //1
SimpleFunction() is equal to
voidvalue (&&) //1
voidvalue (||) //0
What is 'Something?'
and what is happening in SimpleFunction(void)??
Is it special something about Logical operator in unary fold??
#include<iostream>
using namespace std;
template <typename ...Ts>
void SimpleFunction(Ts ... ts)
{
cout<<(ts && ...)<<endl;
cout<<(ts || ...)<<endl;
}
int main()
{
SimpleFunction(); // 1, 0
cout<<endl;
SimpleFunction(1); // 1, 1
cout<<endl;
SimpleFunction(1,2,3); // 1, 1
cout<<endl;
return 0;
}
When the pack contains zero elements, unary && and || folds are defined to return true and false, respectively. In fact, they are two of the only three operators that allow folding with zero elements, with the last one being the comma operator ,, which returns a prvalue of type void. This is why code like nums + ... should usually be rewritten as nums + ... + 0.
When the pack contains one element, a fold expression always expands to the only element.
Why? This is what the standard says. Because it is defined the only way that makes sense. There isn't much more to say other than that.
Related
There are scenarios, that require a guaranteed left to right evaluation sequence when expanding fold expressions into the parameter list of a function/functor.
Example
r = f2(f(x)...)
Problem
f is evaluated in order f(x[n-1]), f(x[n-2]), ... f(x[0]) and it's results passed to f2 the other way around (f(x[0]), f(x[1]), ... f(x[n-1])).
Thoughts
For initializers like initializer{f(x)...} would evaluate and pass in ltr order.
Expanding over the comma operator like (f(x),...) does evaluate left-to-right, but does not allow to return a data convolution.
Something like r = f2(...f(x)) to express a unary left fold'ish evaluation desire is invalid.
Returning into a tuple using an intializer list like std::tuple{f(x)...} and pass the flattened result might work, but appears pretty inefficient having those intermediate steps.
Demo
A simple demo to visualize:
#include <iostream>
#include <tuple>
#include <array>
int main () {
constexpr std::array is{ 0,1,2,3 };
int eval{ 0 };
auto res = std::apply([&](auto&&... v) {
return std::tuple_cat([&](auto& val) {
return std::tuple{ val, eval++ };
} (std::forward<decltype(v)>(v))...);
}, is);
std::apply([](auto&&... v) {((std::cout << v),...); }, res);
}
Output:
as-is: 03122130
to-be: 00112233
How can I achieve a guaranteed left-to-right evaluation and passing into a variadic function order (ideally without overhead of index_sequence)?
On the cppreference article about SFINAE, I came across this syntax which I do not understand:
template <int I> void div(char(*)[I % 2 == 0] = 0) {
// this overload is selected when I is even
}
template <int I> void div(char(*)[I % 2 == 1] = 0) {
// this overload is selected when I is odd
}
I get that its a template function declaration, but I don't understand what the parameters mean. In particular, what are the square brackets in char(*)[I % 2 == 0] = 0 and why is it equal to 0?
Arrays of size 0 are illegal in C++ so a particular overload is chosen based on the value of I: when I is 5, char(*)[I % 2 == 0] would be a pointer to an array of size false, i.e. zero, while the other array pointer is perfectly legal.
= 0 is just a default ignored argument value to save you from typing (0) every time calling this function.
In C++20, it would be much more apparent and straightforward:
template<int I> requires (I % 2 == 0) void div() {
}
And even in C++17:
template<int I> void div() {
if constexpr(I % 2 == 0) {
}
else {
}
}
When I is even then you have (remember that false converts to 0 and true to 1):
template <int I> void div(char(*)[1] = 0) {
// this overload is selected when I is even
}
template <int I> void div(char(*)[0] = 0) {
// this overload is selected when I is odd
}
The second attempts to use an array of size 0 and according to the bullet point on that page:
The following type errors are SFINAE errors:
attempting to create an array of void, array of reference, array of function, array of
negative size, array of non-integral size, or array of size zero.
... that triggers SFINAE and the first overload is selected. The array size is 0 for the first overload when I is odd. Note that the parameter is unnamed. It is not used inside the function, its only purpose is to trigger SFINAE. Calling this function you need not pass the parameter because it has a default, thats the =0. Passing a parameter would be useless because its value isn't used anyhow.
This is a rather arcane example of SFINAE. Since C++11 you would perhaps use std::enable_if together with a template <int I> is_odd; or similar and starting from C++20 you would use concepts.
Here's a part of Eigen documentation:
Matrix3f m;
m << 1, 2, 3,
4, 5, 6,
7, 8, 9;
std::cout << m;
Output:
1 2 3
4 5 6
7 8 9
I couldn't understand how could all the comma separated values be captured by operator<< above. I did a tiny experiment:
cout << "Just commas: ";
cout << 1, 2, 3, 4, 5;
cout << endl;
cout << "Commas in parentheses: ";
cout << ( 1, 2, 3, 4, 5 );
cout << endl;
Predictably (according to my understanding of C++ syntax) only one of the values was captured by operator<< :
Just commas: 1
Commas in parentheses: 5
Thus the title question.
The basic idea is to overload both the << and the , operators.
m << 1 is overloaded to put 1 into m and then returns a special proxy object – call it p – holding a reference to m.
Then p, 2 is overloaded to put 2 into m and return p, so that p, 2, 3 will first put 2 into m and then 3.
A similar technique is used with Boost.Assign, though they use += rather than <<.
This is a possible simplified implementation
struct M3f {
double m[3][3];
struct Loader {
M3f& m;
int i;
Loader(M3f& m, int i) : m(m), i(i) {}
Loader operator , (double x) {
m.m[i/3][i%3] = x;
return Loader(m, i+1);
}
};
Loader operator<<(double x) {
m[0][0] = x;
return Loader(*this, 1);
}
};
The idea is that << returns a Loader instance that waits for second element, and each loader instance uses the comma operator to update the matrix and returns another loader instance.
Note that overloading the comma operator is generally considered a bad idea because the most specific characteristic of the operator is strict left-to-right evaluation order. However when overloaded this is not guaranteed and for example in
m << f(), g(), ...
g() could end up being called before f().
Note that I'm talking about the evaluation order, not about associativity or precedence that are of course maintained also for overloaded versions.
For example g() could be called before f() but the result from f() is guaranteed to be correctly placed in the matrix before the result from g().
The comma itself is an operator in c++ which can be overloaded (and apparently is by eigen). I don't know the exact way eigen implements the overloading but I am sure that you can search for the sources of eigen to look it up.
To your little experient you have to understand how the unoverloaded comma operator works in c++.
The comma operator has the form <statement>,<statement> and is evaluated to whatever the second statement is evaluated to. The operator << has a higher precedence than the operator ,. Because of that the cout is evaluated before the rest of the comma operations are evaluated.
Because , is Left-to-right associative the code (1,2,3,4,5) is equal to ((((1,2),3),4),5) which evaluates to the most right value, which is 5.
I am trying specify a condition by saying that if an array is not equal to an array run loop. So for example:
array1 [1,2,3]
array2 [1,2,3]
Here array1 does equal array2 as the elements in 0 in both arrays are the same, the elements in 1 in both arrays are the same and so on...
The code I have so far doesn't seem to work. Is there a way of comparing two arrays and if all elements in one match all the elements in the second one the condition is true.
Here is my test code:
int C1Mean[3];
int C2Mean[3];
int prv_mean1[3];
int prv_mean2[3];
while (C1Mean[3] = prv_mean1[3] && C2Mean[3] = prv_mean2[3])
{
//code
}
Thanks chaps.
As commented you access your arrays out of bounds, and you are using assignments (single =) instead or comparisons (==).
To compare your arrays (element by element), you can use std::equal :
while(std::equal(std::begin(C1Mean), std::end(C1Mean), std::begin(prv_mean1))
&& std::equal(std::begin(C2Mean), std::end(C2Mean), std::begin(prv_mean2)))
{
...
}
Or without c++11 :
while(std::equal(C1Mean, C1Mean + sizeof C1Mean / sizeof *C1Mean, prv_mean1)
&& std::equal(C2Mean, C2Mean + sizeof C2Mean / sizeof *C2Mean, prv_mean2))
{
...
}
In c++11, you may use std::array, and use ==:
std::array<int, 3> C1Mean;
std::array<int, 3> C2Mean;
std::array<int, 3> prv_mean1;
std::array<int, 3> prv_mean2;
while (C1Mean == prv_mean1 && C2Mean == prv_mean2)
{
//code
}
You are not using comparison operator (==) but assignment (=), so you change the value of CMean[i] in the condition and the condition would be false only when one of prv_mean2 would be equal to zero. And no, you can't compare the whole arrays.
If you are able to use c++11 you can use a generic function. The generic function is:
bool equal(beginIterator, endIterator, beginIterator Other);
This generic function will compare all values in a range. Note that the second array must be at least as long as the first array.
Since an array is nog an object you cannot use arr.begin () and you should use std::begin(arr) and std::end(arr). These functions come with #include.
Furthermore, if you can use c++11 you can also use the standad container std::array or std::vector. Then you can just state arr1 == arr2.
Note: I wrote this on my mobile and didn't check whether the generic function actually works on arrays. I will check this when at home again and eventually remove my post.
You can create a function to compare the two arrays that will return 1 if they are equal and 0 otherwise. Say, for example,
while(areEqual(C1Mean,prv_mean1) && areEqual(C2Mean,prv_mean2))
{
//Perform your task
}
where
int areEqual(int array1[],int array2[])
{
//compare them and return 1 if equal else return 0;
}
It seems like you need a double equals("=="). Try:
while (C1Mean[3] == prv_mean1[3] && C2Mean[3] == prv_mean2[3])
{
//code
}
This is a more specific question based on a question I asked earlier...
If I have a function that takes two parameters (one required, one optional):
an STL container such as a vector
an "optional" comparison function that serves as a relational overload and returns the maximum value, whatever that is, in the vector...
Code:
template <typename Type>
Type FindMax (std::vector<Type> &myVec, int (*cmp)(Type one, Type two) = CallBack)
/.../
WHAT exactly, does the "int (*cmp)(Type one...)" say to the compiler? I want it to say, here's a function to use when comparing two of type Type...ie when using the relational operators <, >, =, etc. If no function is supplied by the user then use the default, otherwise, use what the user provides...
What exactly does the (*cmp)(Type one, Type two) say? Here's a pointer to a function that takes two parameters Type one and Type two? Is there any significance as to what comes after the *, ie could I write (*titsmagee)(Type one, Type two)? I'm assuming the naming convention is to help future readers?
For this to work with a "struct" does anything specific to the potential comparisons to be made need to be stored within said struct?
Thanks!
int (*cmp)(Type one, Type two)
The parameter named cmp is a pointer to a function returning int that takes two parameters of type Type.
struct Foo
{
int x;
};
int compare(Foo x, Foo y)
{
return (x.x == y.x) ? 0 : (x.x > y.x ? 1 : -1);
}
std::vector<Foo> vec;
FindMax<Foo>(vec, &compare);
You need cmp so you can call the comparison function inside FindMax:
template <typename Type>
Type FindMax (std::vector<Type> &myVec, int (*cmp)(Type one, Type two) = CallBack)
{
//whatever loop
max = cmp(myVec[i],myVec[j]) >= 0 ? myVec[i] : myVec[j];
}
EDIT Breaking down the return:
return (x.x == y.x) ? 0 : (x.x > y.x ? 1 : -1);
?: is the ternary conditional operator.
condition ? expression1 : expression2
returns (loosely speaking) expression1 if condition is true, expression2 otherwise.
So what that means is:
if (x.x == y.x)
return 0;
else
if (x.x > y.x)
return 1;
else
return -1;
It's what you expect the comparison function to do. Return 0 for equality, 1 if the first element is bigger than the second, and -1 for the inverse.
EDIT 2
struct Foo
{
int x;
};
//Foo has a member x.
Foo f;
//Create a Foo object called f.
f.x;
//Access the member x of the object