I'm trying to sort a concurrent_vector type, where hits_object is:
struct hits_object{
unsigned long int hash;
int position;
};
Here is the code I'm using:
concurrent_vector<hits_object*> hits;
for(i=0;...){
hits_object *obj=(hits_object*)malloc(sizeof(hits_object));
obj->position=i;
obj->hash=_prevHash[tid];
hits[i]=obj;
}
Now I have filled up a concurrent_vector<hits_object*> called hits.
But I want to sort this concurrent_vector on position property!!!
Here is an example of what's inside a typical hits object:
0 1106579628979812621
4237 1978650773053442200
512 3993899825106178560
4749 739461489314544830
1024 1629056397321528633
5261 593672691728388007
1536 5320457688954994196
5773 9017584181485751685
2048 4321435111178287982
6285 7119721556722067586
2560 7464213275487369093
6797 5363778283295017380
3072 255404511111217936
7309 5944699400741478979
3584 1069999863423687408
7821 3050974832468442286
4096 5230358938835592022
8333 5235649807131532071
I want to sort this based on the first column ("position" of type int). The second column is "hash" of type unsigned long int.
Now I've tried to do the following:
std::sort(hits.begin(),hits.end(),compareByPosition);
where compareByPosition is defined as:
int compareByPosition(const void *elem1,const void *elem2 )
{
return ((hits_object*)elem1)->position > ((hits_object*)elem2)->position? 1 : -1;
}
but I keep getting segmentation faults when I put in the line std::sort(hits.begin(),hits.end(),compareByPosition);
Please help!
Your compare function needs to return a boolean 0 or 1, not an integer 1 or -1, and it should have a strongly-typed signature:
bool compareByPosition(const hits_object *elem1, const hits_object *elem2 )
{
return elem1->position < elem2->position;
}
The error you were seeing are due to std::sort interpreting everything non-zero returned from the comp function as true, meaning that the left-hand side is less than the right-hand side.
NOTE : This answer has been heavily edited as the result of conversations with sbi and Mike Seymour.
int (*)(void*, void*) is the comparator for C qsort() function. In C++ std::sort() the prototype to the comparator is:
bool cmp(const hits_object* lhs, const hits_object* rhs)
{
return lhs->position < rhs->position;
}
std::sort(hits.begin(), hits.end(), &cmp);
On the other hand, you can use std::pair struct, which by default compares its first fields:
typedef std::pair<int position, unsigned long int hash> hits_object;
// ...
std::sort(hits.begin(), hits.end());
Without knowing what concurrent_vector is, I can't be sure what's causing the segmentation fault. Assuming it's similar to std::vector, you need to populate it with hits.push_back(obj) rather than hits[i] = j; you cannot use [] to access elements beyond the end of a vector, or to access an empty vector at all.
The comparison function should be equivalent to a < b, returning a boolean value; it's not a C-style comparison function returning negative, positive, or zero. Also, since sort is a template, there's no need for C-style void * arguments; everything is strongly typed:
bool compareByPosition(hits_object const * elem1, hits_object const * elem2) {
return elem1->position < elem2->position;
}
Also, you usually don't want to use new (and certainly never malloc) to create objects to store in a vector; the simplest and safest container would be vector<hits_object> (and a comparator that takes references, rather than pointers, as arguments). If you really must store pointers (because the objects are expensive to copy and not movable, or because you need polymorphism - neither of which apply to your example), either use smart pointers such as std::unique_ptr, or make sure you delete them once you're done with them.
The third argument you pass to std::sort() must have a signature similar to, and the semantics of, operator<():
bool is_smaller_position(const hits_object* lhs, const hits_object* rhs)
{
return lhs->position < rhs->position;
}
When you store pointers in a vector, you cannot overload operator<(), because smaller-than is fixed for all built-in types.
On a sidenote: Do not use malloc() in C++, use new instead. Also, I wonder why you are not using objects, rather than pointers. Finally, if concurrent_vector is anything like std::vector, you need to explicitly make it expand to accommodate new objects. This is what your code would then look like:
concurrent_vector<hits_object*> hits;
for(i=0;...){
hits_object obj;
obj.position=i;
obj.hash=_prevHash[tid];
hits.push_back(obj);
}
This doesn't look right:
for(i=0;...){
hits_object *obj=(hits_object*)malloc(sizeof(hits_object));
obj->position=i;
obj->hash=_prevHash[tid];
hits[i]=obj;
}
here you already are sorting the array based on 'i' because you set position to i as well as it becomes the index of hits!
also why using malloc, you should use new(/delete) instead. You could then create a simple constructor for the structure to initialize the hits_object
e.g.
struct hits_object
{
int position;
unsigned int hash;
hits_object( int p, unsigned int h ) : position(p), hash(h) {;}
};
then later write instead
hits_object* obj = new hits_object( i, _prevHash[tid] );
or even
hits.push_back( new hits_object( i, _prevHash[tid] ) );
Finally, your compare function should use the same data type as vector for its arguments
bool cmp( hits_object* p1, hits_object* p2 )
{
return p1->position < p2->position;
}
You can add a Lambda instead of a function to std::sort.
struct test
{
int x;
};
std::vector<test> tests;
std::sort(tests.begin(), tests.end(),
[](const test* a, const test* b)
{
return a->x < b->x;
});
Related
I am trying to use std::string as a key in the stxxl::map
The insertion was fine for small number of strings about 10-100.
But while trying to insert large number of strings about 100000 in it, I am getting segmentation fault.
The code is as follows:
struct CompareGreaterString {
bool operator () (const std::string& a, const std::string& b) const {
return a > b;
}
static std::string max_value() {
return "";
}
};
// template parameter <KeyType, DataType, CompareType, RawNodeSize, RawLeafSize, PDAllocStrategy (optional)>
typedef stxxl::map<std::string, unsigned int, CompareGreaterString, DATA_NODE_BLOCK_SIZE, DATA_LEAF_BLOCK_SIZE> name_map;
name_map strMap((name_map::node_block_type::raw_size)*3, (name_map::leaf_block_type::raw_size)*3);
for (unsigned int i = 0; i < 1000000; i++) { /// Inserting 1 million strings
std::stringstream strStream;
strStream << (i);
Console::println("Inserting: " + strStream.str());
strMap[strStream.str()]=i;
}
In here I am unable to identify why I am unable to insert more number of strings. I am getting segmentation fault exactly while inserting "1377". Plus I am able to add any number of integers as key. I feel that the variable size of string might be causing this trouble.
Also I am unable to understand what to return for max_value of the string. I simply returned a blank string.
According to documentation:
CompareType must also provide a static max_value method, that returns a value of type KeyType that is larger than any key stored in map
Because empty string happens to compare as smaller than any other string, it breaks this precondition and may thus cause unspecified behaviour.
Here's a max_value that should work. MAX_KEY_LEN is just an integer which is larger or equal to the length of the longest possible string key that the map can have.
struct CompareGreaterString {
// ...
static std::string max_value() {
return std::string(MAX_KEY_LEN, std::numeric_limits<unsigned char>::max());
}
};
I have finally found the solution to my problem with great help from Timo bingmann, user2079303 and Martin Ba. Thank you.
I would like to share it with you.
Firstly stxxl supports POD only. That means it stores fixed sized structures only. Hence std::string cannot be a key. stxxl::map worked for about 100-1000 strings because they were contained in the physical memory itself. When more strings are inserted it has to write on disk which is internally causing some problems.
Hence we need to use a fixed string using char[] as follows:
static const int MAX_KEY_LEN = 16;
class FixedString {
public:
char charStr[MAX_KEY_LEN];
bool operator< (const FixedString& fixedString) const {
return std::lexicographical_compare(charStr, charStr+MAX_KEY_LEN,
fixedString.charStr, fixedString.charStr+MAX_KEY_LEN);
}
bool operator==(const FixedString& fixedString) const {
return std::equal(charStr, charStr+MAX_KEY_LEN, fixedString.charStr);
}
bool operator!=(const FixedString& fixedString) const {
return !std::equal(charStr, charStr+MAX_KEY_LEN, fixedString.charStr);
}
};
struct comp_type : public std::less<FixedString> {
static FixedString max_value()
{
FixedString s;
std::fill(s.charStr, s.charStr+MAX_KEY_LEN, 0x7f);
return s;
}
};
Please note that all the operators mainly((), ==, !=) need to be overriden for all the stxxl::map functions to work
Now we may define fixed_name_map for map as follows:
typedef stxxl::map<FixedString, unsigned int, comp_type, DATA_NODE_BLOCK_SIZE, DATA_LEAF_BLOCK_SIZE> fixed_name_map;
fixed_name_map myFixedMap((fixed_name_map::node_block_type::raw_size)*5, (fixed_name_map::leaf_block_type::raw_size)*5);
Now the program is compiling fine and is accepting about 10^8 strings without any problem.
also we can use myFixedMap like std::map itself. {for ex: myFixedMap[fixedString] = 10}
If you are using C++11, then as an alternative to the FixedString class you could use std::array<char, MAX_KEY_LEN>. It is an STL layer on top of an ordinary fixed-size C array, implementing comparisons and iterators as you are used to from std::string, but it's a POD type, so STXXL should support it.
Alternatively, you can use serialization_sort in TPIE. It can sort elements of type std::pair<std::string, unsigned int> just fine, so if all you need is to insert everything in bulk and then access it in bulk, this will be sufficient for your case (and probably faster depending on the exact case).
I've been reading all the topics related to sorting arrays of structs, but haven't had any luck as of yet, so I'll just ask. I have a struct:
struct question{
string programNum;
string programDesc;
string programPoints;
string programInput;
string programQuestion;
};
And I populate an array of question in main, and now have an array called questions[] so now I need to write a sort that will sort questions[] based on question.programQuestion. Based on what I've read, this is where I'm at, but I'm not sure if its even close:
int myCompare (const void *v1, const void *v2 ) {
const struct question* p1 = static_cast<const struct question*>(v1);
const struct question* p2 = static_cast<const struct question*>(v2);
if (p1->programQuestion > p2->programQuestion){
return(+1);}
else if (p1->programQuestion < p2->programQuestion){
return(-1);}
else{
return(0);}
}
If this is right I'm not sure how to call it in main. Thanks for any help!
If you're intending to use std::sort to sort this array, you likely want to declare an operator< as a method in this struct. Something like this:
struct question{
string programNum;
string programDesc;
string programPoints;
string programInput;
string programQuestion;
bool operator<( const question &rhs) const;
};
bool question::operator<( const question &rhs ) const
{
return programQuestion < rhs.programQuestion;
}
The comparison function you were attempting to declare above appears to be the type qsort expects, and I would not recommend trying to qsort an array of these struct questions.
Just use std::sort. It's safer, nearly always faster (sometimes by huge margins), and generally easier to get right.
Unless there is some important reason not to do so, I would use a std::vector instead of a plain array. It is easier and safer. You could use the following code to sort your vector:
std::vector<question> questions;
// add some elements to the vector
std::sort(begin(questions), end(questions),
[](const question& q1, const question& q2) {
return q1.programQuestion < q2.programQuestion;
});
This code use some C++11 features. But you could achieve the same in previous versions of C++ by using a function object, or simply by implementing operator< in the struct (assuming you always want to sort such a struct based on that field).
Here is my problem:
I have a struct:
struct point
{
int x;
int y;
};
and then I have an array:
for (int i = 0;i < n;i++)
{
arr[i].x=rand() % n + 1;
}
I defined the quicksort function as follows:
void quicksort(int *a, int left, int right);
and I want to sort the point by X coordinate, so I call the quicksort:
quicksort(arr.x, 0, n-1);
And this is the error message:
error: request for member 'x' in 'arr', which is of non-class type 'point [(((unsigned int)(((int)n) + -0x000000001)) + 1)]'
Sorry if the question is too stupid or badly formulated, the truth is I'm a newbie and I'm really willing to learn as much as possible and I'd be very thankful for your help!
If you always want to sort by x, then you can hard-code it into the sort function, and just pass a pointer to the array to sort:
void quicksort(point * arr, int left, int right) {
// test points with
// if (arr[i].x < arr[j].x) {/* i sorts before j */}
}
quicksort(arr, 0, n-1);
To specify a class member to sort by, you need a pointer-to-member, not a pointer; something like:
void quicksort(point * arr, int point::*member, int left, int right){
// test points with
// if (arr[i].*member < arr[j].*member) {/* i sorts before j */}
}
quicksort(arr, &point::x, 0, n-1);
More generically, you could follow the example of std::sort and accept any comparison functor:
template <typename RandIter, typename Compare>
void quicksort(RandIter begin, RandIter end, Compare compare) {
// test points with
// if (compare(*it1, *it2)) {/* *it1 sorts before *it2 */}
}
quicksort(arr, arr+n,
[](point const &lhs, point const &rhs) {return lhs.x < rhs.x;});
And of course, unless you're learning how to implement a sorting algorithm, just use std::sort.
quicksort(arr,0,n-1);
then within quicksort, try to compare the arr[i].x
There are a few problems with your code.
1. quicksort accepts int* but you try to pass int value x
2. You try to pass int but you actually call an undefined variable arr.x
What you need to do is either call in the form of &arr[i].x, but to accomplish what you want, you probably want to pass the entire struct as a pointer.
You need to pass arr as the parameter, as that is the array to be sorted. arr.x is meaningless. You are not passing the string "arr.x" as a parameter which can somehow be interpreted as meaning sort on the x field - when the compiler sees this, it is looking for an x element of arr, which doesn't exist, as the error message suggests - only the elements of arr (e.g. arr[0]) have x elements (accessed as arr[0].x).
Assuming this is for academic purposes (why else would you declare your own sorting algorithm instead of using one of the ones already implemented with a custom comparator?), you can do this a few ways:
Array
std::array<point, 10> myArray; // declares an array of size 10 for points
template<size_t N>
void quicksort(std::array<point, N>& arr, ...)
{
// implement sort operating on arr
}
Vector
std::vector<point> myVector; // declares a dynamic array/vector of points
void quicksort(std::vector<point>& arr, ...)
{
// implement sort operating on arr
}
If for some god-awful reason, you want to keep it in C:
Legacy
const size_t SIZE = 10;
point arr[SIZE]; // declare an array of 10 points
void quicksort(point* p, const size_t n, ...)
{
// implement sort operating on elements in p passing in SIZE for n
}
I'd rather defined the function as:
void quicksort(void *a,int left,int right, size_t size, int (*fp)(void*,void*));
size is the size of one element of array and fp is a compare function which returns true if the two arguments are equal. Now you can pass the call the function as:
quicksort(arr,0,n-1,sizeof(arr)/sizeof(arr[0]), compare);
where function compare is something like:
int compare(void* a, void* b) { return *((int*)a) >= *((int*)b); }
Rest of the implementation of function is trivial I think.
(almost) never try to fool the system by passing a pointer to a member when you really want to pass a pointer to an object. Do as Grijesh suggested. Passing a member can lead to horrible side effects. For example, quicksort is going to sort all the integers together, regardless of which of them are X's and which are Y's. In milder cases you may get wrong compare criteria, and often hard to debug effects such as incorrect pointer optimization. Just be honest with the compiler and pass the object pointer if you need to pass an object pointer. There are very very very few exceptions, mostly to do with low-level system programming where the "other side' of the function call won't be able to handle the object.
I am writing my own vector class, Vector, with the data members: T* array, size_t vector_size and size_t capacity. I am trying to create a sort() method:
template <class T>
void Vector<T>::sort(bool ascending)
{
std::sort(array,array+vector_size);
if(ascending==false)
std::reverse(array,array+vector_size);
}
It works fine when the elements in the array are of type int, char etc. But when I try to sort a vector consisting of Vector elements it won't compile.
From what I have read I need to define the <operator in some way, but I really don't know how to do that...
I have tried:
template <class T>
bool Vector<T>::operator<(Vector<T> & source) const
{
return (vector_size < source.vector_size);
}
My main look like this:
int main() {
Vector<int> v1(5,1);
Vector<int> v2(7,2);
Vector<int> v3(3,3);
Vector<Vector<int>> v4;
v4 = {v1,v2,v3};
v4.sort(1);
return 0;
}
This is one of the errors I get:
/usr/include/c++/4.6/bits/stl_algo.h:2212:4: error: no match for ‘operator<’ in ‘* __first < __pivot’
You provided a comparison method with the wrong signature. You need to accept a const reference or a value, but not a (modifiable) reference to your type, while the former should be preferred unless it's a primitive type. So the signature of your comparison method should look like this:
template <class T>
bool Vector<T>::operator<(const Vector<T> & source) const
{
return (vector_size < source.vector_size);
}
This is because std::sort (and a lot of other methods) are designed to not modify the contents. This is guaranteed if they take a value (but this will be slow for large types) or a const reference.
Note that you defined the comparison method to compare the size of the vectors, not their contents. All your vectors are of equal length. So they are treated to be equal by std::sort. So std::sort wouldn't change v4... If you intend to compare the contents in a way similar to string comparison (the first entry counts first, if equal then take the next and so on...), use this:
template <class T>
bool Vector<T>::operator<(const Vector<T> & source) const
{
for(int i = 0; i < size && i < source.size; ++i) {
if(*this[i] < source[i])
return true;
else if(source[i] < *this[i])
return false;
}
// You have to decide what to do if the length isn't equal.
// But if the vectors are really equal than return false:
if(size == source.size)
return false;
}
Your forgot a const!
template <class T>
bool Vector<T>::operator<(const Vector<T> & source) const // <- here
{
return (vector_size < source.vector_size);
}
One thing you'd need is to use const in the parameter to your operator, otherwise it can't match anything that is read-only (which would be the common case).
Keep in mind though that sorting vectors-of-vectors would copy entire vectors every time swaps occur. This will not be particularly efficient. If the vectors were stored separately and you had something like vector-of-pointer-to-vector, at least the sorting would be faster.
Be sure to read the definition of "strict weak ordering", too. It is very important for the ordering to be consistent with itself, or standard algorithms like std::sort() can badly misbehave (to the point of corrupting memory in some implementations).
Here's an interesting question about the various quirks of the C++ language. I have a pair of functions, which are supposed to fill an array of points with the corners of a rectangle. There are two overloads for it: one takes a Point[5], the other takes a Point[4]. The 5-point version refers to a closed polygon, whereas the 4-point version is when you just want the 4 corners, period.
Obviously there's some duplication of work here, so I'd like to be able to use the 4-point version to populate the first 4 points of the 5-point version, so I'm not duplicating that code. (Not that it's much to duplicate, but I have terrible allergic reactions whenever I copy and paste code, and I'd like to avoid that.)
The thing is, C++ doesn't seem to care for the idea of converting a T[m] to a T[n] where n < m. static_cast seems to think the types are incompatible for some reason. reinterpret_cast handles it fine, of course, but is a dangerous animal that, as a general rule, is better to avoid if at all possible.
So my question is: is there a type-safe way of casting an array of one size to an array of a smaller size where the array type is the same?
[Edit] Code, yes. I should have mentioned that the parameter is actually a reference to an array, not simply a pointer, so the compiler is aware of the type difference.
void RectToPointArray(const degRect& rect, degPoint(&points)[4])
{
points[0].lat = rect.nw.lat; points[0].lon = rect.nw.lon;
points[1].lat = rect.nw.lat; points[1].lon = rect.se.lon;
points[2].lat = rect.se.lat; points[2].lon = rect.se.lon;
points[3].lat = rect.se.lat; points[3].lon = rect.nw.lon;
}
void RectToPointArray(const degRect& rect, degPoint(&points)[5])
{
// I would like to use a more type-safe check here if possible:
RectToPointArray(rect, reinterpret_cast<degPoint(&)[4]> (points));
points[4].lat = rect.nw.lat; points[4].lon = rect.nw.lon;
}
[Edit2] The point of passing an array-by-reference is so that we can be at least vaguely sure that the caller is passing in a correct "out parameter".
I don't think it's a good idea to do this by overloading. The name of the function doesn't tell the caller whether it's going to fill an open array or not. And what if the caller has only a pointer and wants to fill coordinates (let's say he wants to fill multiple rectangles to be part of a bigger array at different offsets)?
I would do this by two functions, and let them take pointers. The size isn't part of the pointer's type
void fillOpenRect(degRect const& rect, degPoint *p) {
...
}
void fillClosedRect(degRect const& rect, degPoint *p) {
fillOpenRect(rect, p); p[4] = p[0];
}
I don't see what's wrong with this. Your reinterpret-cast should work fine in practice (i don't see what could go wrong - both alignment and representation will be correct, so the merely formal undefinedness won't carry out to reality here, i think), but as i said above i think there's no good reason to make these functions take the arrays by reference.
If you want to do it generically, you can write it by output iterators
template<typename OutputIterator>
OutputIterator fillOpenRect(degRect const& rect, OutputIterator out) {
typedef typename iterator_traits<OutputIterator>::value_type value_type;
value_type pt[] = {
{ rect.nw.lat, rect.nw.lon },
{ rect.nw.lat, rect.se.lon },
{ rect.se.lat, rect.se.lon },
{ rect.se.lat, rect.nw.lon }
};
for(int i = 0; i < 4; i++)
*out++ = pt[i];
return out;
}
template<typename OutputIterator>
OutputIterator fillClosedRect(degRect const& rect, OutputIterator out) {
typedef typename iterator_traits<OutputIterator>::value_type value_type;
out = fillOpenRect(rect, out);
value_type p1 = { rect.nw.lat, rect.nw.lon };
*out++ = p1;
return out;
}
You can then use it with vectors and also with arrays, whatever you prefer most.
std::vector<degPoint> points;
fillClosedRect(someRect, std::back_inserter(points));
degPoint points[5];
fillClosedRect(someRect, points);
If you want to write safer code, you can use the vector way with back-inserters, and if you work with lower level code, you can use a pointer as output iterator.
I would use std::vector or (this is really bad and should not be used) in some extreme cases you can even use plain arrays via pointer like Point* and then you shouldn't have such "casting" troubles.
Why don't you just pass a standard pointer, instead of a sized one, like this
void RectToPointArray(const degRect& rect, degPoint * points ) ;
I don't think your framing/thinking of the problem is correct. You don't generally need to concretely type an object that has 4 vertices vs an object that has 5.
But if you MUST type it, then you can use structs to concretely define the types instead.
struct Coord
{
float lat, long ;
} ;
Then
struct Rectangle
{
Coord points[ 4 ] ;
} ;
struct Pentagon
{
Coord points[ 5 ] ;
} ;
Then,
// 4 pt version
void RectToPointArray(const degRect& rect, const Rectangle& rectangle ) ;
// 5 pt version
void RectToPointArray(const degRect& rect, const Pentagon& pent ) ;
I think this solution is a bit extreme however, and a std::vector<Coord> that you check its size (to be either 4 or 5) as expected with asserts, would do just fine.
I guess you could use function template specialization, like this (simplified example where first argument was ignored and function name was replaced by f(), etc.):
#include <iostream>
using namespace std;
class X
{
};
template<int sz, int n>
int f(X (&x)[sz])
{
cout<<"process "<<n<<" entries in a "<<sz<<"-dimensional array"<<endl;
int partial_result=f<sz,n-1>(x);
cout<<"process last entry..."<<endl;
return n;
}
//template specialization for sz=5 and n=4 (number of entries to process)
template<>
int f<5,4>(X (&x)[5])
{
cout<<"process only the first "<<4<<" entries here..."<<endl;
return 4;
}
int main(void)
{
X u[5];
int res=f<5,5>(u);
return 0;
}
Of course you would have to take care of other (potentially dangerous) special cases like n={0,1,2,3} and you're probably better off using unsigned int's instead of ints.
So my question is: is there a
type-safe way of casting an array of
one size to an array of a smaller size
where the array type is the same?
No. I don't think the language allows you to do this at all: consider casting int[10] to int[5]. You can always get a pointer to it, however, but we can't 'trick' the compiler into thinking a fixed-sized has a different number of dimensions.
If you're not going to use std::vector or some other container which can properly identify the number of points inside at runtime and do this all conveniently in one function instead of two function overloads which get called based on the number of elements, rather than trying to do crazy casts, consider this at least as an improvement:
void RectToPointArray(const degRect& rect, degPoint* points, unsigned int size);
If you're set on working with arrays, you can still define a generic function like this:
template <class T, size_t N>
std::size_t array_size(const T(&/*array*/)[N])
{
return N;
}
... and use that when calling RectToPointArray to pass the argument for 'size'. Then you have a size you can determine at runtime and it's easy enough to work with size - 1, or more appropriate for this case, just put a simple if statement to check if there are 5 elements or 4.
Later if you change your mind and use std::vector, Boost.Array, etc. you can still use this same old function without modifying it. It only requires that the data is contiguous and mutable. You can get fancy with this and apply very generic solutions that, say, only require forward iterators. Yet I don't think this problem is complicated enough to warrant such a solution: it'd be like using a cannon to kill a fly; fly swatter is okay.
If you're really set on the solution you have, then it's easy enough to do this:
template <size_t N>
void RectToPointArray(const degRect& rect, degPoint(&points)[N])
{
assert(N >= 4 && "points requires at least 4 elements!");
points[0].lat = rect.nw.lat; points[0].lon = rect.nw.lon;
points[1].lat = rect.nw.lat; points[1].lon = rect.se.lon;
points[2].lat = rect.se.lat; points[2].lon = rect.se.lon;
points[3].lat = rect.se.lat; points[3].lon = rect.nw.lon;
if (N >= 5)
points[4].lat = rect.nw.lat; points[4].lon = rect.nw.lon;
}
Yeah, there is one unnecessary runtime check but trying to do it at compile time is probably analogous to taking things out of your glove compartment in an attempt to increase your car's fuel efficiency. With N being a compile-time constant expression, the compiler is likely to recognize that the condition is always false when N < 5 and just eliminate that whole section of code.