[eigen] proposal for "clean" output arguments |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/eigen Archives
]
- To: eigen@xxxxxxxxxxxxxxxxxxx
- Subject: [eigen] proposal for "clean" output arguments
- From: Gael Guennebaud <gael.guennebaud@xxxxxxxxx>
- Date: Tue, 18 Aug 2009 16:31:26 +0200
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:date:message-id:subject :from:to:content-type:content-transfer-encoding; bh=CdS4Jz8NZ2IaXxrqgc0hroe3VRsVyIN6D3gHSuK4Nm4=; b=Fd2zTzKnX8golCPCCLE3ONjPX11f+Yo4srvXDBs7ohAUWiKvLMbg8fxMMNO+y3xy/L XoGNxjOHXX5vAAyCitC0vmfhW7BeO51Pjs8BK2EUCpOj9Lcw1ngsOZow2prSHsdbFB8Y 8dEApG7JC+uFHf1xc/n1vjWBDfMZRls33P9rA=
- Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type :content-transfer-encoding; b=M27/xchC2yTxaYvMhXzgF+kDr3WgblEkRd4mHoNJ6CD2fAGouO93f4hM0S/Ic9QmPq Iq6gR8qq00vvXDJZk0h7rpnIMYmvT3Cuwv6yRJ2+yNTFoL6+70ZnfJghnnDiSTfIDH/D yLSQxE81WthDnZ1KYp53tNo2P2Nsx0AfKn/Wo=
Hi all,
here is a proposal to deal with functions having output (or inout)
arguments. Currently the situation is quite a mess:
1 - some take non const references like
TriangularView::solveInPlace(MatrixBase<T>&)
2 - some take pointers like LU::solve(const MatrixBase<T1>& B,
MatrixBase<T2>* X)
3 - some take const references like MatrixBase<T1>::swap(const MatrixBase<T2>&)
The main advantage of the solution 3 is that allows to use temporary
proxies, e.g.:
m.col(i).swap(m.col(j));
The main advantage of solution 2 is that it makes it clear what is an output:
m.lu().solve(b, &x);
The respective drawbacks of each method are pretty obvious I won't
enumerate them one more time...
So what I propose is to add a trivial Output<T> class mimicking a
reference T& that we'll be passed by value. Ok to make thing crystal
clear here is such a Output class:
template<typename T> class Output
{
public:
Output(T& obj) : m_object(obj) { }
operator T&() { return m_object; }
protected:
T& m_object;
};
then we add a output() member function to AnyMatrixBase<> :
Output<Derived> output() { return derived(); }
then the function LU::solve(const MatrixBase<T1>& B, MatrixBase<T2>*
X) can be rewritten:
LU::solve(const MatrixBase<T1>& B, Output<T2> _x) {
T2& x(_x);
// use x
}
and the user sill call it like this:
mat.lu().solve(b, xs.col(2).output());
For in-out argument we can do the same with a InOut<T> class, and a
AnyMatrixBase::inout() function.
Unless I missed something, I think this solution has all the
advantages that someone can expect:
- it is more C++ than pointers,
- it respects constness (unlike const references)
- it allows to use temporary proxies returned by a function (unlike
references and pointers)
- it make it crystal clear what is an output and an in-out arguments
when someone read a piece of code (unlike all other solutions)
The only limitation I can see is how to extend this concept to scalar
type arguments because we cannot have:
double x;
x.output()
Note that if we don't make the ctor of Output explicit, then the
following we'll work:
void foo(Output<float> _x);
float x;
foo(x);
If we want to enforce to have "output" next to x, one possibility is
to add a global function output(T&) and make the ctor of Output
explicit:
float x;
foo(output(x));
Note that such a global function will only work on declared objects,
and not on temporary proxies, that is why we really have to also have
the output() function as a member of AnyMatrixBase...
Of course, another drawback is more API changes...
What do you think ?
gael.