static or not?

M

michael.goossens

Whats the best way to implement this:

BBox BBox::Union(const BBox &b) const{
BBox u;
u.p_min.x = min(p_min.x, b.p_min.x); u.p_min.y = min(p_min.y,
b.p_min.y); u.p_min.z = min(p_min.z, b.p_min.z);
u.p_max.x = max(p_max.x, b.p_max.x); u.p_max.y = max(p_max.y,
b.p_max.y); u.p_max.z = max(p_max.z, b.p_max.z);
return u;
}

or static with two arguments. I'm thinking of making this inline ...
but I don't know why anyone supporting this?
 
A

Alf P. Steinbach

* (e-mail address removed):
Whats the best way to implement this:

BBox BBox::Union(const BBox &b) const{
BBox u;
u.p_min.x = min(p_min.x, b.p_min.x); u.p_min.y = min(p_min.y,
b.p_min.y); u.p_min.z = min(p_min.z, b.p_min.z);
u.p_max.x = max(p_max.x, b.p_max.x); u.p_max.y = max(p_max.y,
b.p_max.y); u.p_max.z = max(p_max.z, b.p_max.z);
return u;
}

or static with two arguments.

Define what your criteria for "best" are.

However, since the above is difficult to read, do

BBox BBox::Union( BBox const& other ) const
{
return BBox(
min( p_min, other.p_min ),
max( p_max, other.p_max )
);
}

It's probably also a good idea to avoid using prefix "p_" for
non-pointers. And generally to avoid Hungarian notation except,
possibly, for the prefix "p" for pointers.

I'm thinking of making this inline ...
but I don't know why anyone supporting this?

Huh?


Cheers, & hth.,

- Alf
 
M

michael.goossens

ooo, great suggestion:
return BBox(min( p_min, other.p_min ), max( p_max, other.p_max ));

I didn't know min and max worked for other types than the primitives.
 
A

Alf P. Steinbach

* (e-mail address removed):
ooo, great suggestion:
return BBox(min( p_min, other.p_min ), max( p_max, other.p_max ));

I didn't know min and max worked for other types than the primitives.

Not sure if that was meant as sarcasm. If it was, then you're learning
something technical now instead of via the previous post, and otherwise
you learned something technical via the previous post. Anyway you
learned or is now learning something technical, and that's good. :)

There is no built-in min and max in C++. The implementations from
<algorithm> can technically be applied to any type that provides a copy
constructor and "<"-comparision, but that's not the functionality needed
above. So you simply define the operators and functions you need.

In this case, in addition to overloads of functions min and max, you
need a suitable BBox constructor.

It goes like this:

#include <algorithm> // std::min, std::max

struct Point3D
{
double x, y, z;

Point3D(): x( 0 ), y( 0 ), z( 0 ) {}

Point3D( double anX, double aY, double aZ )
: x( anX ), y( aY ), z( aZ )
{}
};

struct BoundingBox
{
Point3D minPoint;
Point3D maxPoint;

BoundingBox(
Point3D const& aMinPoint,
Point3D const& aMaxPoint
)
: minPoint( aMinPoint ), maxPoint( aMaxPoint )
{}
};

Point3D min( Point3D const& a, Point3D const& b )
{
using namespace std;
return
Point3D( min( a.x, b.x ), min( a.y, b.y ), min( a.z, b.z ) );
}

// Ditto for max

Whether to use the names "min" and "max" is another matter, which I
think can only be resolved by thinking about what makes sense (or not)
in your problem domain, and whether you plan on using or suspect you
might in future be using std::max or std::min for Point3D.


Cheers, & hth.,

- Alf
 
K

kwikius

Whether to use the names "min" and "max" is another matter, which I
think can only be resolved by thinking about what makes sense (or not)
in your problem domain, and whether you plan on using or suspect you
might in future be using std::max or std::min for Point3D.

FWIW I don't see min and max being useful for points and vectors.

The only possible use is if you treat a vector as a sequence and then
do min or max on each element:

#include <vector>
#include <algorithm>
#include <iostream>

int main()
{
typedef std::vector<double> vect;

vect v1, v2, r_min(3), r_max(3);
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);

v2.push_back(0.5);
v2.push_back(3);
v2.push_back(-1);

typedef double const &(*pf)(double const &, double const &);
std::transform(v1.begin(), v1.end(),
v2.begin(),r_min.begin(),pf(std::min));

for ( std::size_t i = 0; i < r_min.size(); ++i){
std::cout << r_min <<'\n';
}
std::cout << "......\n";
std::transform(v1.begin(), v1.end(),
v2.begin(),r_max.begin(),pf(std::max));

for ( std::size_t i = 0; i < r_max.size(); ++i){
std::cout << r_max <<'\n';
}

}

You can of course also write a version that acts on a tuple.

Alternatively xmin(Pt,Pt), ymin(Pt,Pt),zmin(Pt,Pt) are useful
returning the minimum x and y of the 2 points. In this case its
similar to writing out each iteration of the sequence.

OTOH funnily enough min and max could make sense for a bounding
box :)

regards
Andy Little
 
D

diligent.snail

* (e-mail address removed):



Not sure if that was meant as sarcasm. If it was, then you're learning
something technical now instead of via the previous post, and otherwise
you learned something technical via the previous post. Anyway you
learned or is now learning something technical, and that's good. :)

There is no built-in min and max in C++. The implementations from
<algorithm> can technically be applied to any type that provides a copy
constructor and "<"-comparision, but that's not the functionality needed


Beg to differ. I believe the standard requires the types to be 'less
than comparable' (with < strict weak ordering relationship). Types do
not have to be copy constructible. Do you agree?

Regards.
 
A

Alf P. Steinbach

* (e-mail address removed):
Beg to differ. I believe the standard requires the types to be 'less
than comparable' (with < strict weak ordering relationship). Types do
not have to be copy constructible. Do you agree?

No.

§25.3.7/1 and §25.3.7/4, about std::min and std::max: "Requires: Type T
is LessThanComparable (20.1) and CopyConstructible (20.1.3)."

As you can see the type needs to be copy constructible.

Details as follows:

$20.1.2 table 29 "LessThanComparable requirements"
expression return type requirement
a < b convertible to bool < is a strict weak ordering

$25.3/4 defines a strict weak ordering using a comparision operation
comp(a,b) by defining equiv(a,b) = !comp(a,b) && !comp(b,a) and
requiring transitivity of both, that comp(a,b) && comp(b,c) implies
comp(a,c) and that equiv(a,b) && equiv(b,c) implies equiv(a,c).

§20.1.3 table 30 "CopyConstructible requirements", where t is a value of
type T and u is a value of type T const:
expression return type requirement
T(t) t is equivalent to T(t)
T(u) u is equivalent to T(u)
t.~T()
&t T* denotes the address of t
&u const T* denotes the address of u

requires for CopyConstructible that address operator really yields
address. This is a subtle point, and I didn't even remember it when I
wrote the above. But in practice, only MS code overloads operator&.

I don't think it matters for std::min and std::max, though. ;-)

The main requirement of CopyConstructible is to support copy
construction for both non-const and const argument, first two rows.


Cheers, & hth.,

- Alf
 
D

diligent.snail

* (e-mail address removed):





No.

§25.3.7/1 and §25.3.7/4, about std::min and std::max: "Requires: Type T
is LessThanComparable (20.1) and CopyConstructible (20.1.3)."

As you can see the type needs to be copy constructible.

Details as follows:

$20.1.2 table 29 "LessThanComparable requirements"
expression return type requirement
a < b convertible to bool < is a strict weak ordering

$25.3/4 defines a strict weak ordering using a comparision operation
comp(a,b) by defining equiv(a,b) = !comp(a,b) && !comp(b,a) and
requiring transitivity of both, that comp(a,b) && comp(b,c) implies
comp(a,c) and that equiv(a,b) && equiv(b,c) implies equiv(a,c).

§20.1.3 table 30 "CopyConstructible requirements", where t is a value of
type T and u is a value of type T const:
expression return type requirement
T(t) t is equivalent to T(t)
T(u) u is equivalent to T(u)
t.~T()
&t T* denotes the address of t
&u const T* denotes the address of u

requires for CopyConstructible that address operator really yields
address. This is a subtle point, and I didn't even remember it when I
wrote the above. But in practice, only MS code overloads operator&.

I don't think it matters for std::min and std::max, though. ;-)

The main requirement of CopyConstructible is to support copy
construction for both non-const and const argument, first two rows.

Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

I really do beg your pardon. I have this bad habit of referring to the
the working draft (n2461) rather than the 1997 document, which is much
much different.

Looks like the CopyConstructible will be dropped for std::min and
std::max; but for current implementations it is a requirement.

Thank you for the detailed reply.
 
K

kwikius

I really do beg your pardon. I have this bad habit of referring to the
the working draft (n2461) rather than the 1997 document, which is much
much different.

Looks like the CopyConstructible will be dropped for std::min and
std::max; but for current implementations it is a requirement.

Thank you for the detailed reply.

Could add that its an unnecessary requirement AFAICS. (Perhaps the
return type was changed from value to const reference at some point.)

#include <algorithm>
#include <iostream>

struct my{
explicit my (double v_in) : v (v_in){};
double v;
private :
my ( my const &);

};

inline bool operator <
(my const & lhs, my const & rhs)
{
return lhs.v < rhs.v;
}


int main()
{
my x(1),y(2);
my const & r = std::min(x,y);
// my z = std::max(x,y); //error private cctor
std::cout << r.v <<'\n';
}

regards
Andy Little
 
M

michael.goossens

Be nice dudes :), I did it without the min / max thing because that
would mean that points / vectors were getting an ordering in space,
which is mathematicaly incorrect.
 
A

Alf P. Steinbach

* kwikius:
Could add that its an unnecessary requirement AFAICS. (Perhaps the
return type was changed from value to const reference at some point.)

#include <algorithm>
#include <iostream>

struct my{
explicit my (double v_in) : v (v_in){};
double v;
private :
my ( my const &);

};

inline bool operator <
(my const & lhs, my const & rhs)
{
return lhs.v < rhs.v;
}


int main()
{
my x(1),y(2);
my const & r = std::min(x,y);

Consider instead

my const& r = std::min( x, my(2) );

Note: incorrectly compiles with MSVC 7.1, is diagnosed with g++ 3.4.4
and of course with Comeau.

I first learned about this silly requirement of class having an
accessible copy constructor when (among a great many others) helping to
review Andrei Alexandrescu's Mojo library, a way to implement "move"
construction (library-implemented RVO) in current standard C++. That
attempt sort of stranded on this requirement, that the implementation
should be free to make a temporary copy instead of just providing a
reference directly to the rvalue. Happily, will be removed in C++0x
:), but, of course, that yields more Potential Dangers, like if the
code above was accepted with std::min implemented with ordinary current
references instead of new-fangled moving rvalue references.

Uh.

I wonder if the code above will be valid in C++0x, and if so, how the
heck the compiler could implement the necessary lifetime extension for
the temporary?

// my z = std::max(x,y); //error private cctor
std::cout << r.v <<'\n';
}

Off-topic, but: Comeau Online's error message is ungrokkable while
g++'s error message is simple and to the point. Difference: that Comeau
implements concept checking. The C++0x technology that's meant to
provide /simpler/ error messages!


Cheers, & hth.,

- Alf
 
K

kwikius

* kwikius:




Consider instead

   my const& r = std::min( x, my(2) );

Ouch!. But Isnt whether 'my' is copy constructible or not irrelevant
here. It will still screw up just the same ?

hmmm....

I wonder if the code above will be valid in C++0x, and if so, how the
heck the compiler could implement the necessary lifetime extension for
the temporary?

hmm.... Mental note!

I'll look at the move constructible widget when it materialises,
meanwhile my overloads of min/max will return by value.

:)

regards
Andy Little
 
K

kwikius

Be nice dudes :), I did it without the min / max thing because that
would mean that points / vectors were getting an ordering in space,
which is mathematicaly incorrect.

I'm with you on this one dude :)

regards
Andy Little
 
K

kwikius

kwikius wrote :





Consider instead

   my const& r = std::min( x, my(2) );

Ouch. hang about. But what difference does it make whether the
arguments are copy constructible or not?

Or is the result r referencing a temporary copied from one of the
inputs or what?
Note: incorrectly compiles with MSVC 7.1, is diagnosed with g++ 3.4.4
and of course with Comeau.

I first learned about this silly requirement of class having an
accessible copy constructor when (among a great many others) helping to
review Andrei Alexandrescu's Mojo  library, a way to implement "move"
construction (library-implemented RVO) in current standard C++.  That
attempt sort of stranded on this requirement, that the implementation
should be free to make a temporary copy instead of just providing a
reference directly to the rvalue.  Happily, will be removed in C++0x
:), but, of course, that yields more Potential Dangers, like if the
code above was accepted with std::min implemented with ordinary current
references instead of new-fangled moving rvalue references.

Uh.

I wonder if the code above will be valid in C++0x, and if so, how the
heck the compiler could implement the necessary lifetime extension for
the temporary?

hmmm... mental note. When this move widget materialises I'll
investigate, meanwhile maybe my overloads of min/max will return by
value...

Off-topic, but:  Comeau Online's error message is ungrokkable while
g++'s error message is simple and to the point.  Difference: that Comeau
implements concept checking.  The C++0x technology that's meant to
provide /simpler/ error messages!

Not exactly a fair comparison. "concept checking" is pretty primitive,
just some function pointer to a function exercising the expression. It
was originally demoed in the "design and evolution of C++" book
AFAIK. It fails really because you still get an error message in some
remote place IIRC, wherever the concept checking function is defined.

For true Concepts the ball keeps moving, but it was shockingly strict
last time I looked. Your type may have the correct bits and pieces but
if you dont say it does in the correct way, you will get an error
message at that point. It would be interesting to try redoing the
above in ConceptGcc to see what output you get. Maybe I will try it
myself...

regards
Andy Little
 
A

Alf P. Steinbach

* kwikius:
Ouch. hang about. But what difference does it make whether the
arguments are copy constructible or not?

A class type rvalue passed as actual argument to T const& formal
argument must have an accessible copy constructor (formally), per the
current standard, because the implementation is free to create a new
temporary, or any number of temporaries, and pass reference to that.

Or is the result r referencing a temporary copied from one of the
inputs or what?

Would depend on the implementation, if it accepted the code.

With some copyable type the above example (with arguments transposed to
yield reference to temporary as std::min result) would just be UB.


Cheers,

- Alf
 
K

kwikius

A class type rvalue passed as actual argument to T const& formal
argument must have an accessible copy constructor (formally), per the
current standard, because the implementation is free to create a new
temporary, or any number of temporaries, and pass reference to that.


Would depend on the implementation, if it accepted the code.

With some copyable type the above example (with arguments transposed to
yield reference to temporary as std::min result) would just be UB.

Its only undefined behaviour if the value of the temporary is less
than the value of the l_value for std::min, which is actually worse!

The fact that its only undefined behaviour if you pass in a temporary
is neither here nor there, as the contract in the function signature
( the const ref args) by convention says to me that passing in a
temporary is fine.

According to what you say you could theoretically prevent U.B, by
making your copy ctor private. It should prevent this case ( its
caught by gcc 3.4), but may be impractical!

Rule. Don't return by const reference anything you passed in by const
reference! returning by non const reference what you passed in by non
const reference seems OK though.

Looking through my own code,I don't see anywhere that I return by
const reference in free functions.

My verdict is that std::min/max are needlesly allowing undefined
behaviour. There is a simple solution, which is to return by value.

regards
Andy Little
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,183
Messages
2,570,967
Members
47,518
Latest member
RomanGratt

Latest Threads

Top