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.
Related
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.
--Quick Before
So before anyone says this question has been answered on another post it hasn't... It was a homework question in the other post and the original question was never answered only told they were wrong.
--Question
I am trying to overload the >> operator to be able to pass in n-number of variables seperated by commas into an object like so...
Mat M = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
I am trying to reuse their usage of the comma seperated argument list but I can't seem to get it to work.
When I overload the << operator like so
void operator<< (const double& is)
{
std::cout << "hiya " << is << std::endl;
}
and attempt to use it like so
mat << 1.0, 2.0;
only the first value is passed to the operator... The second value is never 'used' as I believe that << has a higher presidence than ,
So my question is what are they doing in libraries like eigen and openCV to be able to have this functionality. I have looked through their code to attempt to understand it but it appears to require a deeper understanding of how C++ works that I don't have and I was hoping someone here could shed some light on it.
Thanks in advance for any advice.
You'll have to overload the insertion operator (<<) and the comma operator (,) such that
mat << 1.0, 2.0;
is translated as:
mat.operator<<(1.0).operator,(2.0);
or
operator,(operator<<(mat, 1.0), 2.0);
Here's a demonstrative program that illustrates the idea without doing anything useful.
struct Foo
{
};
Foo& operator<<(Foo& f, double)
{
std::cout << "In operator<<(Foo& f, double)\n";
return f;
}
Foo& operator,(Foo& f, double)
{
std::cout << "In operator,(Foo& f, double)\n";
return f;
}
int main()
{
Foo f;
f << 10, 20, 30;
}
and its output
In operator<<(Foo& f, double)
In operator,(Foo& f, double)
In operator,(Foo& f, double)
You would have to create a temporary from the first argument and surround the entire comma list in parenthesis:
myObj >> (some_temporary(3), 1, ...);
which would require that some_temporary be either a type or helper-function-returning-object that overloads the comma operator and your >> would need to be able to take that type. Otherwise the precedence of >> would "win" and therefore be evaluated before the comma expression is seen.
An uglier alternative would be to have your >> return a type that overloads operator ,() but I believe the first is preferable (actually, I would say this entire scheme is un-preferable).
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.
Hi I came across this piece of code. It demonstrates how to work with matrix structures of the dlib library.
According to this one can initialize a matrix structure by:
M = 54.2, 7.4, 12.1,
1, 2, 3,
5.9, 0.05, 1;
How can this be possible in C++?
Is this some kind of operator overloading?
Logic
This is possible by overloading operator, (operator comma), and for example make it push new floating point values into M.
A thing to notice is that operator, should always have at least one parameter of class type, therefore you'll have to create a class that is implicitly convertible to floating point value (for example via a non explicit constructor with 1 argument of type double or float).
Example
For example we'll try to do this for a wrapper type over an std::vector and we'll try to make M = 1, 2, 3, 4, 5 a valid expression which results in an std::vector with those elements in sequence. You'll see that this is easily applicable to the matrix example you gave.
A thing to remember is that operator= has more precedence over operator, (as shown in this table of operator precedence); therefore M = 1, 2, 3, 4, 5 will really be parsed as: (((((M = 1), 2), 3), 4), 5).
Given that, we'll start by creating our class container with an operator= that takes a single value and pushes it into the container:
template<typename ValueType>
struct container {
explicit container(std::size_t n) {
vec.reserve(n);
}
container& operator=(ValueType a) {
vec.push_back(a);
return (*this);
}
std::vector<ValueType> vec;
};
At this point we can define operator, as:
template<typename ValueType>
container<ValueType>& operator,(container<ValueType>& m, ValueType a) {
m.vec.push_back(a);
return m;
}
which just pushes back a new element value.
And now you can easily see that the following works just fine and prints 1 2 3 4 5:
int main() {
container<int> M(5);
M = 1, 2, 3, 4, 5;
for (auto i : M.vec) std::cout << i << ' ';
}
Live demo
Considerations
I discourage this technique as much as possible. It forces you to have weird semantic for other operators, such as operator= and really seem to add nothing to a simple use of std::initializer_list<T>.
A saner example would be to have operator= as follows:
container& operator=(std::initializer_list<ValueType> a) {
std::copy(begin(a), end(a), back_inserter(vec));
return (*this);
}
and then simply use brackets:
int main() {
container<int> M(5);
M = { 1, 2, 3, 4, 5 };
for (auto i : M.vec) std::cout << i << ' ';
}
Live demo
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.