I am searching for some help in next situation:
I have some class and some method in it, syntax is like this:
class SomeClass {
public:
void doSomething(int *a);
};
So I want to call this method like
SomeClass::doSomething({ 0, 1, 2, 3, 4 });
Is it possible in any language?
Any (C++, C, obj-c, obj-c++) implementation is welcome!
I know that this initialization block is a body of array, like
int *a = { 0, 1, 2, 3, 4 };
SomeClass::doSomething(a);
But interface will look great, I think, if there will be no temp variables before function calls (as we don't need to know the type of parameter in class-client). So, is there any chance to make this?
In C99 this works:
functionThatTakesIntPtrOrArray( (int []){ 1, 2, 3, 4 } );
..and similar things can be done with structs.
This is about C++11 initializer lists (section 18.9).
void foo (std :: initializer_list <int> inputs) {
for (auto i : inputs) {
// ...
}
}
foo ({10, 20, 30});
Only the compiler can create an initializer list, but you can treat it like a standard STL-style container with begin(), end(), size(), and random-access iterators.
std::vector (and I expect some other containers) can now be constructed with initializer lists, so
std :: vector <std :: string> foo {"a", "b"};
is equivalent to
std :: vector <std :: string> foo;
foo .push_back ("a");
foo .push_back ("b");
except that it may perform fewer allocations. Note that the const char* have been turned into std::string automagically.
If initializer_list is not available, and the arrays are mostly small, there is another option, overloading << operator for std::vector like this:
template <typename T>
inline std::vector<T> operator <<( const std::vector<T>& vec, const T& val ) {
std::vector<T> result(vec);
result.push_back(val);
return result;
}
With that, you can do this:
void foo (const std::vector<int>& inputs) {
// ...
}
foo ( std::vector<int>() << 10 << 20 << 30 );
There is a price to pay for this convenience of single line initialization and not having to specify vector size. A copy of the prior vector is created for every element that is added, making running time at least quadratic in vector size -- that's why this is best suited for short vectors and cases when performance does not matter. There is a better solution for C++11, as pointed out in spraff's answer.
one can initialize a temporary array as a function parameter like so
// onboard LED
const byte LED_RED = 36;
const byte LED_BLUE = 34;
const byte LED_GREEN = 35;
void turnOffLedAll(){
// TURN OFF ALL LED
digitalWrite(LED_RED, LOW);
digitalWrite(LED_BLUE, LOW);
digitalWrite(LED_GREEN, LOW);
}
void statusLED(byte led[], byte stat, byte time=0) {
turnOffLedAll();
// turn ON LED
for(int i=0; i<(sizeof(led)/sizeof(led[0])); i++){
digitalWrite(led[i], stat);
}
if (time>0){
delay(time*1000);
turnOffLedAll();
}
}
Considering the functions above an inline array initialization as a function parameter can be done like this:
statusLED((byte*)(const byte[]){LED_RED}, LOW, 0);
Related
I am confused about the output in the following program about the vec in Test. Why it's a vector with size 100 instead of 1? I thought std::vector<T> var{a} is the same as std::vector<T> var = {a}.
#include <iostream>
#include <vector>
using namespace std;
struct Value {
int a;
int b;
};
class Test {
public:
std::vector<struct Value> vec{100};
};
class Test2 {
public:
std::vector<int> vec{100};
};
int main()
{
Test test;
std::cout << "test size: " << test.vec.size() << std::endl;
Test2 test2;
std::cout << "test2 size: " << test2.vec.size();
return 0;
}
Output:
test size: 100
test2 size: 1
std::vector has a constructor with a std::initializer_list<T> argument. When using an initializer list like {100} this constructor will always take priority, if it is applicable.
For a std::vector<int> the initializer {100} is compatible with std::initializer_list<int> so that constructor will be used. It will create a vector containing the collection {100} which is a single int with the value 100.
For std::vector<Value> the initializer {100} is NOT compatible with a std::initializer_list<Value> argument. Value has no converting constructor for turning an int to a Value so you cannot construct a std::initializer_list<Value> from {100}. You can verify that this conversion is not allowed with this example. The compiler will try to take a lower priority constructor instead, and will use the constructor which initializes 100 default constructed Value.
If you add a Value::Value(int) constructor or use {{100}} as the initializer for Test2 you will find that the std::vector<Value> will now only contain a single element. In both cases, the initializer list is convertible to std::initializer_list<Value> and that constructor will now be used.
As you discovered the meaning of {100}, changes for T == int.
To answer your question briefly:
The 100 in vector<Value>{100} cannot be interpreted as a Value and therefore the size constructor takes precedence.
If you insist, {100} can be interpreted as Value, so you may need an extra curly braces, vector<Value>{ {100} }.
See the illustration here: https://godbolt.org/z/xcMT1oc5z
My advice, avoiding further discussion on legalities, is the following:
To keep the meaning across types, initialize consistently parenthesis for size-initialization and brackets for element(s), which forces you to do this:
std::vector<int> vec = std::vector<int>(100);
And in general:
std::vector<T> vec = std::vector<T>(100);
In this case 100 is always the size.
This may not be a totally helpful answer, but I decided to put a breakpoint in the class declaration for vector in the STD library.
Answer
In the definition of a vector, there are 3 ways it handles the assignment.
A struct will provide a value-construction, where as an int will be assigned as a sized range construction.
It reads std::vector<struct> vect{100}; as building a vector of length 100, while std::vector<int> vect{100}; is acting similarly vect.insert(v.end(),100);
This is based on the type of object passed in for .
For information's sake, the final option is taking a given value, and assigning it to a number of spots. So if you had 100, "x", it would put "x" into your vector 100 times.
The Journey
What I learned from this is that there's a point where your vector takes a size_type input and a _Valty&& input (which I don't know what that is yet. Will be looking it up later) and provides a construction between 3 different args.
My best guess would be that your struct is filling in for 1-args path and acts as a length declaration, while int as a native type falls into the 2-args path and acts as a value assignment.
The sizeof(Value) may == 0, while the size of an int will be 1.
Edit: I guessed 1 and 2 (or _Count == 0, and Count == 1), however I was wrong about this. It's _Count == 0 and _Count == 2. Which was very interesting.
template <class... _Valty>
_CONSTEXPR20 void _Construct_n(_CRT_GUARDOVERFLOW const size_type _Count, _Valty&&... _Val) {
// Dispatches between the three sized constructions.
// 1-arg -> value-construction, e.g. vector(5)
// 2-arg -> fill, e.g. vector(5, "meow")
// 3-arg -> sized range construction, e.g. vector{"Hello", "Fluffy", "World"}
auto& _Al = _Getal(); //////////////// For test1, _Count is 100, for test2, _Count is 1;
auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Al);
auto& _My_data = _Mypair._Myval2;
_Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _My_data);
if (_Count != 0) {
_Buy_nonzero(_Count);
_Tidy_guard<vector> _Guard{this};
// This one happens with a struct
if constexpr (sizeof...(_Val) == 0) {
_My_data._Mylast = _Uninitialized_value_construct_n(_My_data._Myfirst, _Count, _Al);
} else
if constexpr (sizeof...(_Val) == 1) {
_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Valty..., const _Ty&>);
_My_data._Mylast = _Uninitialized_fill_n(_My_data._Myfirst, _Count, _Val..., _Al);
} else
// This one happens with an int
if constexpr (sizeof...(_Val) == 2) {
_My_data._Mylast = _Uninitialized_copy(_STD forward<_Valty>(_Val)..., _My_data._Myfirst, _Al);
} else {
static_assert(_Always_false<_Ty>, "Should be unreachable");
}
_Guard._Target = nullptr;
}
_Proxy._Release();
}
What's really interesting as that it appears to be happening when the Allocator reference is assigned. I'm by no means an expert in the language, but I really wanted to figure this puzzle one! Thanks for the interesting challenge!
If you've never walked through a class definition before, I would recommend trying it out.
Why we can initialize array with
int a[]={1,2,3};
but we can't assign data to existing array
a = {2,3,4};
?
Is it possible to make a function that takes const array as a parameter, and call it to assign variable in one line?
pseudocode:
int a[] = {1,2,3};
myfunc(a, (int){2,3,4});
void myfunc(int &array1, const int array2)
{
copy(array2,array1);
}
Since C-array can't do that.
C-array doesn't have assignment operator available.
Reason is purely historical. First of all memory at that time was very limited. Creating a feature to easy copy of array was considered as a waist of memory and time so it was not a priority. In fact it was more important to ensure that arrays are passed by pointer (not by value), that is why array in C and C++ decay to pointer to value. Also most of other languages of that time didn't had such capability. Later the backward comparability took over and such feature was never introduced.
Use more modern std::array where this is possible.
std::array<int, 4> a { 1, 3, 4, -2 };
a = { -4, -2, 0, 0 };
https://wandbox.org/permlink/PLeISvwWd8WtfZ3L
Yes, you can write a function-template that deduces the size of the arrays
template<size_t N>
void myfunc(int (&a)[N], int const (&b)[N])
{
std::copy(b, b + N, a);
}
Note that this allows the second parameter to be deduced from a brace-init list as you want. An additional advantage is that you can't get the sizes wrong.
Now you can copy in a single line
int main()
{
int a[] = {1,2,3};
for (auto i : a)
std::cout << i; // 1 2 3
myfunc(a, {2,3,4});
for (auto i : a)
std::cout << i; // 2 3 4
myfunc(a, {2,3,4,5}); // error, as it should be
}
I have classes in the style of Class1 (see code). An enum and a function to get all the values from the enum. The values (FOO_1, FOO_2 etc) differ from Class to Class as well as the number of values (sizeof(Foos)).
I call the function once to get the sizeof the enum, reserve memory and with the second call I want to get all the values to *pFoos (2,1,6 in the sample code).
Is there a better way then using an array with all the values in it (size_t arr[3] ={FOO_1 , FOO_X, FOO_BAR })?
class Class1{
enum Foos{
FOO_1 = 2,
FOO_X = 1,
FOO_BAR = 6
}
};
Class1::GetFoos(size_t* pFoos, size_t* pSize)
{
size_t len = sizeof(Foos);
if (len > *pSize)
{ //Call function once to get the size
*pSize= len ;
return -1;
}
for(size_t i = 0; i< *pSize; i++)
{
//copy all enum values to pFoos
}
};
Disclaimer: shameless plug – I am the author.
Reflective enums are possible in C++. I wrote a header-only library that captures a bunch of "patterns" at compile time and gives you syntax like this:
ENUM(Class1, int, FOO_1 = 2, FOO_X = 1, FOO_BAR = 6)
size_t count = Class1::_size;
for (size_t index = 0; index < Class1::_size; ++index)
do_anything(Class1::_values()[index]);
What it does internally is use the macro to generate an array of the values that you have declared, kind of like in your question, and use a bunch of other tricks to allow you to use initializers naturally. It then provides iterators and other things on top of the array.
Here is a link: https://github.com/aantron/better-enums
EDIT – internals
Here is a pseudocode sketch of what it does internally. The reason I am only giving a "sketch" is because there are a bunch of issues to consider when doing this portably. I will touch on all the most important elements.
ENUM(Class1, int, FOO_1 = 2, FOO_X = 1, FOO_BAR = 6)
notionally expands to
struct Class1 {
enum _enumerated { FOO_1 = 2, FOO_X = 1, FOO_BAR = 6 };
// Fairly obvious methods for how to iterate over _values and
// _names go here. Iterators are simply pointers into _values
// and _names below.
static size_t _size = sizeof(_values) / sizeof(int);
int _value;
};
int _values[] = {(fix_t<Class1>)Class1::FOO_1 = 2,
(fix_t<Class1>)Class1::FOO_X = 1,
(fix_t<Class1>)Class1::FOO_BAR = 6};
const char *_names[] = {"FOO_1 = 2", "FOO_X = 1", "FOO_BAR = 6"};
This is done by using variadic macros and stringization. The methods that deal with strings treat not only \0, but also space and equals as terminators, which allows them to ignore the initializers in the stringized constants that you see in _names.
The type fix_t is necessary because having assignments inside an array initializer is not valid C++. What that type does is take on the value of the enum, then ignore the assignment by an overloaded assignment operator, and then return the original value. A sketch:
template <typename Enum>
struct fix_t {
Enum _value;
fix_t(Enum value) : _value(value) { }
const fix_t& operator =(int anything) const { return *this; }
operator Enum() const { return _value; }
};
This makes the _values array possible declare even in the presence of initializers.
Of course, these arrays need to be prefixed so that you can have more than one enum like this. They also need to have the same as "extern inline" linkage for functions, so that they are shared between multiple compilation units.
Until c++ will get reflection you will not get any data from your enum! Simply you can not get "all" values from an enum. A enum is simply a kind of namespace where some constants can be defined and may be enumerated automatically. Not more at all. You have no text representation, no count information, no value to text information!
Is there a better way then using an array with all the values in it (size_t arr[3] ={FOO_1 , FOO_X, FOO_BAR })?
If you're tagging the question as C++ I advise you to give up with the C way of doing things, so the better way to do this in C++ is using a std::vector:
class Class1{
enum Foos{
FOO_1 = 2,
FOO_X = 1,
FOO_BAR = 6
};
public:
std::vector<int> GetFoos()
{
// return all enum values
return {FOO_1, FOO_X, FOO_BAR};
}
};
You can use it this way:
Class1 c1;
auto foos = c1.GetFoos();
std::cout << "I have " << c1.size() << " foos:\n";
for (const auto &foo : foos) std::cout << foo << '\n';
If you don't want to create the vector at runtime, you can create it once declaring it static:
class Alpha{
enum Alphas{
BETA = 0b101010,
GAMMA = 0x20,
EPSILON = 050
};
static const std::vector<int> m_alphas;
public:
const std::vector<int> &GetAlphas()
{
return m_alphas;
}
};
// https://isocpp.org/wiki/faq/ctors#explicit-define-static-data-mems
const std::vector<int> Alpha::m_alphas = {BETA, GAMMA, EPSILON};
Live demo
I know that is a burden to maintain but since there's no way to iterate the values of an enum, all the code that tries to iterate them is a burden as well.
Maybe in the following answer you can find something useful to iterate enums in a better way for your goals:
enum to string in modern C++ and future C++17.
One of the interview questions asked me to "write the prototype for a C function that takes an array of exactly 16 integers" and I was wondering what it could be? Maybe a function declaration like this:
void foo(int a[], int len);
Or something else?
And what about if the language was C++ instead?
In C, this requires a pointer to an array of 16 integers:
void special_case(int (*array)[16]);
It would be called with:
int array[16];
special_case(&array);
In C++, you can use a reference to an array, too, as shown in Nawaz's answer. (The question asks for C in the title, and originally only mentioned C++ in the tags.)
Any version that uses some variant of:
void alternative(int array[16]);
ends up being equivalent to:
void alternative(int *array);
which will accept any size of array, in practice.
The question is asked - does special_case() really prevent a different size of array from being passed. The answer is 'Yes'.
void special_case(int (*array)[16]);
void anon(void)
{
int array16[16];
int array18[18];
special_case(&array16);
special_case(&array18);
}
The compiler (GCC 4.5.2 on MacOS X 10.6.6, as it happens) complains (warns):
$ gcc -c xx.c
xx.c: In function ‘anon’:
xx.c:9:5: warning: passing argument 1 of ‘special_case’ from incompatible pointer type
xx.c:1:6: note: expected ‘int (*)[16]’ but argument is of type ‘int (*)[18]’
$
Change to GCC 4.2.1 - as provided by Apple - and the warning is:
$ /usr/bin/gcc -c xx.c
xx.c: In function ‘anon’:
xx.c:9: warning: passing argument 1 of ‘special_case’ from incompatible pointer type
$
The warning in 4.5.2 is better, but the substance is the same.
There are several ways to declare array-parameters of fixed size:
void foo(int values[16]);
accepts any pointer-to-int, but the array-size serves as documentation
void foo(int (*values)[16]);
accepts a pointer to an array with exactly 16 elements
void foo(int values[static 16]);
accepts a pointer to the first element of an array with at least 16 elements
struct bar { int values[16]; };
void foo(struct bar bar);
accepts a structure boxing an array with exactly 16 elements, passing them by value.
& is necessary in C++:
void foo(int (&a)[16]); // & is necessary. (in C++)
Note : & is necessary, otherwise you can pass array of any size!
For C:
void foo(int (*a)[16]) //one way
{
}
typedef int (*IntArr16)[16]; //other way
void bar(IntArr16 a)
{
}
int main(void)
{
int a[16];
foo(&a); //call like this - otherwise you'll get warning!
bar(&a); //call like this - otherwise you'll get warning!
return 0;
}
Demo : http://www.ideone.com/fWva6
I think the simplest way to be typesafe would be to declare a struct that holds the array, and pass that:
struct Array16 {
int elt[16];
};
void Foo(struct Array16* matrix);
You already got some answers for C, and an answer for C++, but there's another way to do it in C++.
As Nawaz said, to pass an array of N size, you can do this in C++:
const size_t N = 16; // For your question.
void foo(int (&arr)[N]) {
// Do something with arr.
}
However, as of C++11, you can also use the std::array container, which can be passed with more natural syntax (assuming some familiarity with template syntax).
#include <array>
const size_t N = 16;
void bar(std::array<int, N> arr) {
// Do something with arr.
}
As a container, std::array allows mostly the same functionality as a normal C-style array, while also adding additional functionality.
std::array<int, 5> arr1 = { 1, 2, 3, 4, 5 };
int arr2[5] = { 1, 2, 3, 4, 5 };
// Operator[]:
for (int i = 0; i < 5; i++) {
assert(arr1[i] == arr2[i]);
}
// Fill:
arr1.fill(0);
for (int i = 0; i < 5; i++) {
arr2[i] = 0;
}
// Check size:
size_t arr1Size = arr1.size();
size_t arr2Size = sizeof(arr2) / sizeof(arr2[0]);
// Foreach (C++11 syntax):
for (int &i : arr1) {
// Use i.
}
for (int &i : arr2) {
// Use i.
}
However, to my knowledge (which is admittedly limited at the time), pointer arithmetic isn't safe with std::array unless you use the member function data() to obtain the actual array's address first. This is both to prevent future modifications to the std::array class from breaking your code, and because some STL implementations may store additional data in addition to the actual array.
Note that this would be most useful for new code, or if you convert your pre-existing code to use std::arrays instead of C-style arrays. As std::arrays are aggregate types, they lack custom constructors, and thus you can't directly switch from C-style array to std::array (short of using a cast, but that's ugly and can potentially cause problems in the future). To convert them, you would instead need to use something like this:
#include <array>
#include <algorithm>
const size_t N = 16;
std::array<int, N> cArrayConverter(int (&arr)[N]) {
std::array<int, N> ret;
std::copy(std::begin(arr), std::end(arr), std::begin(ret));
return ret;
}
Therefore, if your code uses C-style arrays and it would be infeasible to convert it to use std::arrays instead, you would be better off sticking with C-style arrays.
(Note: I specified sizes as N so you can more easily reuse the code wherever you need it.)
Edit: There's a few things I forgot to mention:
1) The majority of the C++ standard library functions designed for operating on containers are implementation-agnostic; instead of being designed for specific containers, they operate on ranges, using iterators. (This also means that they work for std::basic_string and instantiations thereof, such as std::string.) For example, std::copy has the following prototype:
template <class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last,
OutputIterator result);
// first is the beginning of the first range.
// last is the end of the first range.
// result is the beginning of the second range.
While this may look imposing, you generally don't need to specify the template parameters, and can just let the compiler handle that for you.
std::array<int, 5> arr1 = { 1, 2, 3, 4, 5 };
std::array<int, 5> arr2 = { 6, 7, 8, 9, 0 };
std::string str1 = ".dlrow ,olleH";
std::string str2 = "Overwrite me!";
std::copy(arr1.begin(), arr1.end(), arr2.begin());
// arr2 now stores { 1, 2, 3, 4, 5 }.
std::copy(str1.begin(), str1.end(), str2.begin());
// str2 now stores ".dlrow ,olleH".
// Not really necessary for full string copying, due to std::string.operator=(), but possible nonetheless.
Due to relying on iterators, these functions are also compatible with C-style arrays (as iterators are a generalisation of pointers, all pointers are by definition iterators (but not all iterators are necessarily pointers)). This can be useful when working with legacy code, as it means you have full access to the range functions in the standard library.
int arr1[5] = { 4, 3, 2, 1, 0 };
std::array<int, 5> arr2;
std::copy(std::begin(arr1), std::end(arr1), std::begin(arr2));
You may have noticed from this example and the last that std::array.begin() and std::begin() can be used interchangeably with std::array. This is because std::begin() and std::end() are implemented such that for any container, they have the same return type, and return the same value, as calling the begin() and end() member functions of an instance of that container.
// Prototype:
template <class Container>
auto begin (Container& cont) -> decltype (cont.begin());
// Examples:
std::array<int, 5> arr;
std::vector<char> vec;
std::begin(arr) == arr.begin();
std::end(arr) == arr.end();
std::begin(vec) == vec.begin();
std::end(vec) == vec.end();
// And so on...
C-style arrays have no member functions, necessitating the use of std::begin() and std::end() for them. In this case, the two functions are overloaded to provide applicable pointers, depending on the type of the array.
// Prototype:
template <class T, size_t N>
T* begin (T(&arr)[N]);
// Examples:
int arr[5];
std::begin(arr) == &arr[0];
std::end(arr) == &arr[4];
As a general rule of thumb, if you're unsure about whether or not any particular code segment will have to use C-style arrays, it's safer to use std::begin() and std::end().
[Note that while I used std::copy() as an example, the use of ranges and iterators is very common in the standard library. Most, if not all, functions designed to operate on containers (or more specifically, any implementation of the Container concept, such as std::array, std::vector, and std::string) use ranges, making them compatible with any current and future containers, as well as with C-style arrays. There may be exceptions to this widespread compatibility that I'm not aware of, however.]
2) When passing a std::array by value, there can be considerable overhead, depending on the size of the array. As such, it's usually better to pass it by reference, or use iterators (like the standard library).
// Pass by reference.
const size_t N = 16;
void foo(std::array<int, N>& arr);
3) All of these examples assume that all arrays in your code will be the same size, as specified by the constant N. To make more your code more implementation-independent, you can either use ranges & iterators yourself, or if you want to keep your code focused on arrays, use templated functions. [Building on this answer to another question.]
template<size_t SZ> void foo(std::array<int, SZ>& arr);
...
std::array<int, 5> arr1;
std::array<int, 10> arr2;
foo(arr1); // Calls foo<5>(arr1).
foo(arr2); // Calls foo<10>(arr2).
If doing this, you can even go so far as to template the array's member type as well, provided your code can operate on types other than int.
template<typename T, size_t SZ>
void foo(std::array<T, SZ>& arr);
...
std::array<int, 5> arr1;
std::array<float, 7> arr2;
foo(arr1); // Calls foo<int, 5>(arr1).
foo(arr2); // Calls foo<float, 7>(arr2).
For an example of this in action, see here.
If anyone sees any mistakes I may have missed, feel free to point them out for me to fix, or fix them yourself. I think I caught them all, but I'm not 100% sure.
Based on Jonathan Leffler's answer
#include<stdio.h>
void special_case(int (*array)[4]);
void anon(void){
int array4[4];
int array8[8];
special_case(&array4);
special_case(&array8);
}
int main(void){
anon();
return 0;
}
void special_case(int (*array)[4]){
printf("hello\n");
}
gcc array_fixed_int.c &&./a.out will yield warning:
array_fixed_int.c:7:18: warning: passing argument 1 of ‘special_case’ from incompatible pointer type [-Wincompatible-pointer-types]
7 | special_case(&array8);
| ^~~~~~~
| |
| int (*)[8]
array_fixed_int.c:2:25: note: expected ‘int (*)[4]’ but argument is of type ‘int (*)[8]’
2 | void special_case(int (*array)[4]);
| ~~~~~~^~~~~~~~~
Skip warning:
gcc -Wno-incompatible-pointer-types array_fixed_int.c &&./a.out
I have an array of edges, which is defined as a C-style array of doubles, where every 4 doubles define an edge, like this:
double *p = ...;
printf("edge1: %lf %lf %lf %lf\n", p[0], p[1], p[2], p[3]);
printf("edge2: %lf %lf %lf %lf\n", p[4], p[5], p[6], p[7]);
So I want to use std::sort() to sort it by edge length. If it was a struct Edge { double x1, y1, x2, y2; }; Edge *p;, I would be good to go.
But in this case, the double array has a block size that is not expressed by the pointer type. qsort() allows you to explicitly specify the block size, but std::sort() infers the block-size by the pointer type.
For performance reasons (both memory-usage and CPU), let's say that it's undesirable to create new arrays, or transform the array somehow. For performance reasons again, let's say that we do want to use std::sort() instead of qsort().
Is it possible to call std::sort() without wasting a single CPU cycle on transforming the data?
Possible approach:
An obvious approach is to try to force-cast the pointer:
double *p = ...;
struct Edge { double arr[4]; };
Edge *p2 = reinterpret_cast<Edge*>(p);
std::sort(...);
But how do I make sure the data is aligned properly? Also, how do I make sure it will always be aligned properly on all platforms and architectures?
Or can I use a typedef double[4] Edge;?
How about having a reordering vector? You initialize vector with 1..N/L, pass std::sort a comparator that compares elements i1*L..i1*L+L to i2*L..i2*L+L, and when your vector is properly sorted, reorder the C array according to new order.
In response to comment: yes things get complicated, but it may just be good complication! Take a look here.
You can use a "stride iterator" for this. A "stride iterator" wraps another iterator and an integer step size. Here's a simple sketch:
template<typename Iter>
class stride_iterator
{
...
stride_iterator(Iter it, difference_type step = difference_type(1))
: it_(it), step_(step) {}
stride_iterator& operator++() {
std::advance(it_,step_);
return *this;
}
Iter base() const { return it_; }
difference_type step() const { return step_; }
...
private:
Iter it_;
difference_type step_;
};
Also, helper functions like these
template<typename Iter>
stride_iterator<Iter> make_stride_iter(
Iter it,
typename iterator_traits<Iter>::difference_type step)
{
return stride_iterator<Iter>(it,step);
}
template<typename Iter>
stride_iterator<Iter> make_stride_iter(
stride_iterator<Iter> it,
typename iterator_traits<Iter>::difference_type step)
{
return stride_iterator<Iter>(it.base(),it.step() * step);
}
should make it fairly easy to use stride iterators:
int array[N*L];
std::sort( make_stride_iter(array,L),
make_stride_iter(array,L)+N );
Implementing the iterator adapter all by yourself (with all operators) is probably not a good idea. As Matthieu pointed out, you can safe yourself a lot of typing if you make use of Boost's iterator adapter tools, for example.
Edit:
I just realized that this doesn't do what you wanted since std::sort will only exchange the first element of each block. I don't think there's an easy and portable solution for this. The problem I see is that swapping "elements" (your blocks) cannot be (easily) customized when using std::sort. You could possibly write your iterator to return a special reference type with a special swap function but I'm not sure whether the C++ standard guarantees that std::sort will use a swap function that is looked up via ADL. Your implementation may restrict it to std::swap.
I guess the best answer is still: "Just use qsort".
For the new question, we need to pass in sort() a kind of iterator that will not only let us compare the right things (i.e. will make sure to take 4 steps through our double[] each time instead of 1) but also swap the right things (i.e. swap 4 doubles instead of one).
We can accomplish both by simply reinterpreting our double array as if it were an array of 4 doubles. Doing this:
typedef double Edge[4];
doesn't work, since you can't assign an array, and swap will need to. But doing this:
typedef std::array<double, 4> Edge;
or, if not C++11:
struct Edge {
double vals[4];
};
satisfies both requirements. Thus:
void sort(double* begin, double* end) {
typedef std::array<double, 4> Edge;
Edge* edge_begin = reinterpret_cast<Edge*>(begin);
Edge* edge_end = reinterpret_cast<Edge*>(end);
std::sort(edge_begin, edge_end, compare_edges);
}
bool compare_edges(const Edge& lhs, const Edge& rhs) {
// to be implemented
}
If you're concerned about alignment, can always just assert that there's no extra padding:
static_assert(sizeof(Edge) == 4 * sizeof(double), "uh oh");
I don't remember exactly how to do this, but if you can fake anonymous functions, then you can make a comp(L) function that returns the version of comp for arrays of length L... that way L becomes a parameter, not a global, and you can use qsort. As others mentioned, except in the case where your array is already sorted, or backwards or something, qsort is going to be pretty much just as fast as any other algorithm. (there's a reason it's called quicksort after all...)
It's not part of any ANSI, ISO, or POSIX standard, but some systems provide the qsort_r() function, which allows you to pass an extra context parameter to the comparison function. You can then do something like this:
int comp(void *thunk, const void *a, const void *b)
{
int L = (int)thunk;
// compare a and b as you would normally with a qsort comparison function
}
qsort_r(array, N, sizeof(int) * L, (void *)L, comp);
Alternatively, if you don't have qsort_r, you can use the callback(3) package from the ffcall library to create closures at runtime. Example:
#include <callback.h>
void comp_base(void *data, va_alist alist)
{
va_start_int(alist); // return type will be int
int L = (int)data;
const void *a = va_arg_ptr(alist, const void*);
const void *b = va_arg_ptr(alist, const void*);
// Now that we know L, compare
int return_value = comp(a, b, L);
va_return_int(alist, return_value); // return return_value
}
...
// In a function somewhere
typedef int (*compare_func)(const void*, const void*);
// Create some closures with different L values
compare_func comp1 = (compare_func)alloc_callback(&comp_base, (void *)L1);
compare_func comp2 = (compare_func)alloc_callback(&comp_base, (void *)L2);
...
// Use comp1 & comp2, e.g. as parameters to qsort
...
free_callback(comp1);
free_callback(comp2);
Note that the callback library is threadsafe, since all parameters are passed on the stack or in registers. The library takes care of allocating memory, making sure that memory is executable, and flushing the instruction cache if necessary to allow dynamically generated code (that is, the closure) to be executed at runtime. It supposedly works on a large variety of systems, but it's also quite possible that it won't work on yours, either due to bugs or lack of implementation.
Also note that this adds a little bit of overhead to the function call. Each call to comp_base() above has to unpack its arguments from the list passed it (which is in a highly platform-dependent format) and stuff its return value back in. Most of the time, this overhead is miniscule, but for a comparison function where the actual work performed is very small and which will get called many, many times during a call to qsort(), the overhead is very significant.
std::array< std::array<int, L>, N > array;
// or std::vector< std::vector<int> > if N*L is not a constant
std::sort( array.begin(), array.end() );
I'm not sure if you can achieve the same result without a lot more work. std::sort() is made to sort sequences of elements defined by two random access iterators. Unfortunately, it determines the type of the element from the iterator. For example:
std::sort(&array[0], &array[N + L]);
will sort all of the elements of array. The problem is that it assumes that the subscripting, increment, decrement, and other indexing operators of the iterator step over elements of the sequence. I believe that the only way that you can sort slices of the array (I think that this is what you are after), is to write an iterator that indexes based on L. This is what sellibitze has done in the stride_iterator answer.
namespace
{
struct NewCompare
{
bool operator()( const int a, const int b ) const
{
return a < b;
}
};
}
std::sort(array+start,array+start+L,NewCompare);
Do test with std::stable_sort() on realistic data-sets - for some data mixes its substantially faster!
On many compilers (GCC iirc) there's a nasty bite: the std::sort() template asserts that the comparator is correct by testing it TWICE, once reversed, to ensure the result is reversed! This will absolutely completely kill performance for moderate datasets in normal builds. The solution is something like this:
#ifdef NDEBUG
#define WAS_NDEBUG
#undef NDEBUG
#endif
#define NDEBUG
#include <algorithm>
#ifdef WAS_NDEBUG
#undef WAS_NDEBUG
#else
#undef NDEBUG
#endif
Adapted from this excellent blog entry: http://www.tilander.org/aurora/2007/12/comparing-stdsort-and-qsort.html
Arkadiy has the right idea. You can sort in place if you create an array of pointers and sort that:
#define NN 7
#define LL 4
int array[NN*LL] = {
3, 5, 5, 5,
3, 6, 6, 6,
4, 4, 4, 4,
4, 3, 3, 3,
2, 2, 2, 2,
2, 0, 0, 0,
1, 1, 1, 1
};
struct IntPtrArrayComp {
int length;
IntPtrArrayComp(int len) : length(len) {}
bool operator()(int* const & a, int* const & b) {
for (int i = 0; i < length; ++i) {
if (a[i] < b[i]) return true;
else if (a[i] > b[i]) return false;
}
return false;
}
};
void sortArrayInPlace(int* array, int number, int length)
{
int** ptrs = new int*[number];
int** span = ptrs;
for (int* a = array; a < array+number*length; a+=length) {
*span++ = a;
}
std::sort(ptrs, ptrs+number, IntPtrArrayComp(length));
int* buf = new int[number];
for (int n = 0; n < number; ++n) {
int offset = (ptrs[n] - array)/length;
if (offset == n) continue;
// swap
int* a_n = array+n*length;
std::move(a_n, a_n+length, buf);
std::move(ptrs[n], ptrs[n]+length, a_n);
std::move(buf, buf+length, ptrs[n]);
// find what is pointing to a_n and point it
// to where the data was move to
int find = 0;
for (int i = n+1; i < number; ++i) {
if (ptrs[i] == a_n) {
find = i;
break;
}
}
ptrs[find] = ptrs[n];
}
delete[] buf;
delete[] ptrs;
}
int main()
{
for (int n = 0; n< NN; ++n) {
for (int l = 0; l < LL; ++l) {
std::cout << array[n*LL+l];
}
std::cout << std::endl;
}
std::cout << "----" << std::endl;
sortArrayInPlace(array, NN, LL);
for (int n = 0; n< NN; ++n) {
for (int l = 0; l < LL; ++l) {
std::cout << array[n*LL+l];
}
std::cout << std::endl;
}
return 0;
}
Output:
3555
3666
4444
4333
2222
2000
1111
----
1111
2000
2222
3555
3666
4333
4444
A lot of these answers seem like overkill. If you really have to do it C++ style, using jmucchiello's example:
template <int Length>
struct Block
{
int n_[Length];
bool operator <(Block const &rhs) const
{
for (int i(0); i < Length; ++i)
{
if (n_[i] < rhs.n_[i])
return true;
else if (n_[i] > rhs.n_[i])
return false;
}
return false;
}
};
and then sort with:
sort((Block<4> *)&array[0], (Block<4> *)&array[NN]);
It doesn't have to be any more complicated.