Re: User defined conversion to builtin type gives l-value?
On Apr 12, 8:41 pm, Arne Mertz <n...@arne-mertz.de> wrote:
James Kanze schrieb:
On Apr 11, 9:34 pm, Arne Mertz <n...@arne-mertz.de> wrote:
SG schrieb:
On 11 Apr., 18:30, Arne Mertz <n...@arne-mertz.de> wrote:
You either write
return T(u) / t; // suggested previously
or you write
T temp = u;
temp /= t;
return temp;
Unfortunately, *I* write nothing there. The function is
part of the boost libraries (boost/operators.hpp, line
240). It is only used in the absence of two #defines, so as
a workaround I had to check for those defines and set one
of them explicitly.
Have you actually read the documentation of
Boost::operators? They provide operators for user defined
classes. Not in the best way, of course---you really want
to use the Barton and Nackman trick here, and provide them
as friends of a base class. But that's not the point here:
if you instantiate e.g. operator/ with X as the first
template argument, then it is a pre-condition that X has a
member function operator/=. Otherwise, you're not using the
library as specified.
Well, as far as I can see the documentation says only that the
operation has to compile, not that operator /= must be a
member.
That's true in the tables, but the introductory documentation
does make a point of them being member functions. (Of course,
logically, it should be documented as a constraint.)
Of course, I can't find any way you could reasonably use the
library as it is specified---you need operator/ to be
somewhere where ADL will find it, and ADL will not look into
namespace boost. (That's why the Barton and Nackman trick
is preferred.) And of course, there really isn't any good
reason to not support classes with operator/= as a free
function---arguably, it should be a free function, because
that is the only way to make it require an lvalue.
In my case it is indeed a free function - it is the builtin
operator/=(double, double). The problem occurs with
dividable2_left<double, X>, which implements
double operator-(X const&, double const&) by converting the X
into double and applying /=
I'm not sure I understand. You can't overload /= for double,
double. The compiler won't even consider user defined overloads
in such cases.
I know that the mixed arithmetic templates <T,U> should be
declared base classes of T, not of U, but as T is double I
derive U from those templates to make the lookup possible. As
I said, the short form is only used when BOOST_HAS_NRVO and
BOOST_FORCE_SYMMETRIC_OPERATORS are not #defined so at the
moment I make sure that one of the two is defined:
The source is such a confused mess of conditional compilations
that I can't make heads or tails of it. What I think is that
you have two variants (after expansion of all the macros):
T
operator/( T lhs, U const& rhs )
{
return lhs /= rhs ;
}
and
T
operator/( T const& lhs, U const& rhs )
{
T nrv( lhs ) ;
nrv /= rhs ;
return nrv ;
}
Both of these should work with T == double. (The first isn't
what I'd consider good coding style, but apparently, it's an
optimization for compilers which don't support NRVO.)
The case you're interested in is more complex, however, since
they do an implicit conversion on the value to the left of the
/=. There's no way this can work for a built-in type.
#include <boost/config.hpp>
#ifndef BOOST_HAS_NRVO
#define BOOST_FORCE_SYMMETRIC_OPERATORS
#endif
#include <boost/operators.hpp>
I think that BOOST_FORCE_SYMMETRIC_OPERATORS is designed to be
set by you. Just define it, before including any Boost headers,
and I think you should be OK. (I can't test it, because for my
compiler here, BOOST_HAS_NRVO is set, systematically, so unless
I use a hack like the above to undefine it, your code works.)
But what puzzles me is that if the left template argument is a
user defined type with a free operator/=, the problem does not
occur:
class Y {};
Y& operator/= (Y& lhs, Y const&) { return lhs; }
struct X : public boost::dividable2_left<Y, X>
{
operator Y() const {return Y();}
};
//injected by boost:
//Y boost::operator/ (Y vonst& lhs, X const& rhs)
//{ return X(lhs) /= rhs; }
//
int main()
{
X x;
Y y;
Y e = x / y;
}
Yes it does.
In the beginning of the thread, you mentioned VC++, I think.
I'm not sure, but I seem to recall hearing that VC++ doesn't
enforce the rule about not binding a temporary to a non-const
reference. In which case, the above will work (but the built-in
operator won't, because the rules for lvalues are enforced).
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34