I have tried to create a template function that does some weighted sampling within a Monte Carlo simulation. It is below. input_data will either be a statically-allocated array (i.e. data[33]), a dynamically-allocated array, or a vector.
template <class myType>
int init_roulette_calcs(myType &input_data, int inputlength, int *(&output_cdf), int highclassix, int weight)
{
sort(input_data, input_data + inputlength); //where the error occurs
//other code:
output_cdf = new int [inputlength];
int k = 1;
for (int i = 0; i < inputlength; i++)
{
output_cdf[i] = k;
if (i+1 < highclassix) k++;
else k += weight;
}
return output_cdf[inputlength-1];
}
The code will not compile because the template function could not deduce the argument for the call to sort. This may be a stupid question, but what do I need to do to ensure that sort can work properly?
Error 4 error C2784: 'std::_Vb_iterator<_Alloc> std::operator
+(_Alloc::difference_type,std::_Vb_iterator<_Alloc>)' : could not deduce template argument for
'std::_Vb_iterator<_Alloc>' from 'int' j:\rdm\lrgv_2011-07-21\lrgv_src\lrgv.h 398
Thanks in advance for your help.
If you put in an array, the array name is essentially a pointer to the first element, and the array name + x is the poitner to the xth element - so you have this part correct.
The problem is that this is not the case for a vector, which is why you need to use the .begin() and .end() functions to get the pointer to these locations.
You could try sorting by pulling the addresses of the dereferenced start/end elements - that might let you treat a vector the same as an array.
In your code, input_data is a reference, but sort would need it to be a pointer to the start of an array. It should be:
int init_roulette_calcs(myType input_data[], int inputlength, …
Although it would be proper STL usage to make such a template that the user can provide any kind of random access begin and end iterators instead. Thus you could later switch to a vector or any other container that sort can work on…
template <class InputIterator>
int init_roulette_calcs(InputIterator begin, InputIterator end, int *(&output_cdf), int highclassix, int weight)
sort(&input_data, &input_data + inputlength);
^^^ ^^^
I hope the argument you're passing is actually a reference to the first element in an array.
Related
I was writing this code for finding Kth smallest element in array where l= starting index and r = ending index is given to us as input parameter in function.
class Solution{
public:
int kthSmallest(int arr[], int l, int r, int k) {
//code here
arr.sort(l,l+r+1);
int count =1,i=1,var =0;
while(count<=k)
{
var = arr[i];
count++;
i++;
}
return var;
}
};
I tried to use sort function in my code but this code is giving error in my sort function ,given below which is not understood by me.
prog.cpp: In member function int Solution::kthSmallest(int*, int, int, int):
prog.cpp:18:13: error: request for member sort in arr, which is of non-class type int*
arr.sort(l,l+r+1);
^
arr is type int *, so a primitive type and a primitive type don't have any member function. So arr don't have any sort() member function, so it cause an error.
If you want to sort arr, use std::sort from <algorithm>.
std::sort(arr + l, arr + r + 1);
Another way is to use the std::nth_element algorithm, it will give you the element at the position in the array if the array where sorted.
To use it you need iterator so you will have to convert your C array arr[] into a std::array if you don't want heap allocation or a std::vector if you want to be more flexible.
Note: if you use C++ 20 you can use std::ranges::nth_element
In C++, arrays like arr are not objects, so they have no members like sort that you can access using the dot operator.
Instead, try using std::sort from the <algorithm> header:
#include <algorithm>
std::sort(arr + l, arr + r + 1);
This example assumes that:
l is the leftmost index you're sorting.
r is the rightmost index.
both l and r are valid indices for arr.
Suppose a n-dimensional array that is passed as template argument and should be traversed in order to save it to a file. First of all I want to find out the size of the elements the array consists of. Thereto I try to dereference the pointers until I get the first element at [0][0][0]...[0]. But I already fail at this stage:
/**
* #brief save a n-dimensional array to file
*
* #param arr: the n-level-pointer to the data to be saved
* #param dimensions: pointer to array where dimensions of <arr> are stored
* #param n: number of levels / dimensions of <arr>
*/
template <typename T>
void save_array(T arr, unsigned int* dimensions, unsigned int n){
// how to put this in a loop ??
auto deref1 = *arr;
auto deref2 = *deref1;
auto deref3 = *deref2;
// do this n times, then derefn is equivalent to arr[0]...[0], 42 should be printed
std::cout << derefn << std::endl;
/* further code */
}
/*
* test call
*/
int main(){
unsigned int dim[4] = {50, 60, 80, 50}
uint8_t**** arr = new uint8_t***[50];
/* further initialization of arr, omitted here */
arr[0][0][0][0] = 42;
save_array(arr, dim, 4);
}
When I think of this from a memory perspective I want to perform a n-indirect load of a given address.
I saw a related question that was asked yesterday:
Declaring dynamic Multi-Dimensional pointer
This would help me a lot as well. One comment states it is not possible since types of all expressions must be known at compile-time. In my case there's actually known everything, all callers of save_array will have n hardcoded before passing it. So I think it could be just a matter of defining stuff at the right place what I am yet not able to.
I know I am writing C-style code in C++ and there could be options to achieve this with classes etc., but my question is: Is it possible to achieve n-level pointer dereference by an iterative or recursive approach? Thanks!
First of all: Do you really need a jagged array? Do you want to have some sort of sparse array? Because otherwise, could you not just flatten your n-dimensional structure into a single, long array? That would not just lead to much simpler code, but most likely also be more efficient.
That being said: It can be done for sure. For example, just use a recursive template and rely on overloading to peel off levels of indirection until you get to the bottom:
template <typename T>
void save_array(T* arr, unsigned int* dimensions)
{
for (unsigned int i = 0U; i < *dimensions; ++i)
std::cout << ' ' << *arr++;
std::cout << std::endl;
}
template <typename T>
void save_array(T** arr, unsigned int* dimensions)
{
for (unsigned int i = 0U; i < *dimensions; ++i)
save_array(*arr, dimensions + 1);
}
You don't even need to explicitly specify the number of indirections n, since that number is implicitly given by the pointer type.
You can do basically the same trick to allocate/deallocate the array too:
template <typename T>
struct array_builder;
template <typename T>
struct array_builder<T*>
{
T* allocate(unsigned int* dimensions) const
{
return new T[*dimensions];
}
};
template <typename T>
struct array_builder<T**> : private array_builder<T*>
{
T** allocate(unsigned int* dimensions) const
{
T** array = new T*[*dimensions];
for (unsigned int i = 0U; i < *dimensions; ++i)
array[i] = array_builder<T*>::allocate(dimensions + 1);
return array;
}
};
Just this way around, you need partial specialization since the approach using overloading only works when the type can be inferred from a parameter. Since functions cannot be partially specialized, you have to wrap it in a class template like that. Usage:
unsigned int dim[4] = { 50, 60, 80, 50 };
auto arr = array_builder<std::uint8_t****>{}.allocate(dim);
arr[0][0][0][0] = 42;
save_array(arr, dim);
Hope I didn't overlook anything; having this many indirections out in the open can get massively confusing real quick, which is why I strongly advise against ever doing this in real code unless absolutely unavoidable. Also this raw usage of new all over the place is anything but great. Ideally, you'd be using, e.g., std::unique_ptr. Or, better yet, just nested std::vectors as suggested in the comments…
Why not just use a data structure like tree with multiple child nodes.
Suppose you need to store n dimensional array values, create a node pointing to the first dimension. Say your first dimension length is 5 then you have 5 child nodes and if your 2nd dimension size is 10. Then for each of these 5 node you have 10 child nodes and so on....
Some thing like,
struct node{
int index;
int dimension;
vector<node*> children;
}
It will be easier to traverse through tree and is much cleaner.
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 trying to learn C++ function templates.I am passing an array as pointer to my function template. In that, I am trying to find the size of an array. Here is the function template that I use.
template<typename T>
T* average( T *arr)
{
T *ansPtr,ans,sum = 0.0;
size_t sz = sizeof(arr)/sizeof(arr[0]);
cout<<"\nSz is "<<sz<<endl;
for(int i = 0;i < sz; i++)
{
sum = sum + arr[i];
}
ans = (sum/sz);
ansPtr = &ans;
return ansPtr;
}
The cout statement displays the size of arr as 1 even when I am passing the pointer to an array of 5 integers. Now I know this might be a possible duplicate of questions to which I referred earlier but I need a better explanation on this.
Only thing I could come up with is that since templates are invoked at runtime,and sizeof is a compile time operator, compiler just ignores the line
int sz = sizeof(arr)/sizeof(arr[0]);
since it does not know the exact type of arr until it actually invokes the function.
Is it correct or am I missing something over here? Also is it reliable to send pointer to an array to the function templates?
T *arr
This is C++ for "arr is a pointer to T". sizeof(arr) obviously means "size of the pointer arr", not "size of the array arr", for obvious reasons. That's the crucial flaw in that plan.
To get the size of an array, the function needs to operate on arrays, obviously not on pointers. As everyone knows (right?) arrays are not pointers.
Furthermore, an average function should return an average value. But T* is a "pointer to T". An average function should not return a pointer to a value. That is not a value.
Having a pointer return type is not the last offense: returning a pointer to a local variable is the worst of all. Why would you want to steal hotel room keys?
template<typename T, std::size_t sz>
T average( T(&arr)[sz])
{
T ans,sum = 0.0;
cout<<"\nSz is "<<sz<<endl;
for(int i = 0;i < sz; i++)
{
sum = sum + arr[i];
}
ans = (sum/sz);
return ans;
}
If you want to be able to access the size of a passed parameter, you'd have to make that a template parameter, too:
template<typename T, size_t Len>
T average(const T (&arr)[Len])
{
T sum = T();
cout<<"\nSz is "<<Len<<endl;
for(int i = 0;i < Len; i++)
{
sum = sum + arr[i];
}
return (sum/Len);
}
You can then omit the sizeof, obviously. And you cannot accidentially pas a dynamically allocated array, which is a good thing. On the downside, the template will get instantiated not only once for every type, but once for every size. If you want to avoid duplicating the bulk of the code, you could use a second templated function which accepts pointer and length and returns the average. That could get called from an inline function.
template<typename T>
T average(const T* arr, size_t len)
{
T sum = T();
cout<<"\nSz is "<<len<<endl;
for(int i = 0;i < len; i++)
{
sum = sum + arr[i];
}
return (sum/len);
}
template<typename T, size_t Len>
inline T average(const T (&arr)[Len])
{
return average(arr, Len);
}
Also note that returning the address of a variable which is local to the function is a very bad idea, as it will not outlive the function. So better to return a value and let the compiler take care of optimizing away unneccessary copying.
Arrays decay to pointers when passed as a parameter, so you're effectively getting the size of the pointer. It has nothing to do with templates, it's how the language is designed.
Others have pointed out the immediate errors, but IMHO, there are two
important points that they haven't addresses. Both of which I would
consider errors if they occurred in production code:
First, why aren't you using std::vector? For historical reasons, C
style arrays are broken, and generally should be avoided. There are
exceptions, but they mostly involve static initialization of static
variables. You should never pass C style arrays as a function
argument, because they create the sort of problems you have encountered.
(It's possible to write functions which can deal with both C style
arrays and std::vector efficiently. The function should be a
function template, however, which takes two iterators of the template
type.)
The second is why aren't you using the functions in the standard
library? Your function can be written in basically one line:
template <typename ForwardIterator>
typename ForwardIterator::value_type
average( ForwardIterator begin, ForwardIterator end )
{
return std::accumulate( begin, end,
typename::ForwardIterator::value_type() )
/ std::distance( begin, end );
}
(This function, of course, isn't reliable for floating point types,
where rounding errors can make the results worthless. Floating point
raises a whole set of additional issues. And it probably isn't really
reliable for the integral types either, because of the risk of overflow.
But these are more advanced issues.)
I am getting this error and another error too ** "IntelliSense: no instance of function template matches the argument list"** when compiling the following code
I know there might be logic mistakes in my function but I need to solve this error first to be able to debug my function .
#include <iostream>
using namespace std;
template<class T>
T myMax (T& arr ,int arrStart ,int arrSize)
{
if(arrStart==arrSize-1)
return arr[arrSize];
int median = (arrStart+arrSize)/2 ;
T left , right , maximum ;
left = max(arr,arrStart , median);
right = max(arr , median+1 , arrSize-1) ;
if (left>right)
maximum = left;
else
maximum = right ;
return maximum ;
}
void main()
{
int arrSize = 5;
int arr[] = {1,3,4,6,22};
int x;
x = myMax(arr,0,arrSize);
}
The argument for parameter arr is of type int[5]. Since you didn't specify a template argument for T when calling myMax, argument deduction happens and T is deduced to be int[5].
Then the compiler attempts to specialize the function template with T = int[5] (i.e., it tries to replace all instances of T with int[5]). This fails because the function returns a T by value but it is not possible to return an array (like int[5]) by value.
It looks like you want T to be the element type. If that is the case, you can explicitly take a reference to the array, e.g.,
template<class T, unsigned N>
T myMax (T (&arr)[N])
Though, a more idiomatic way to write the function would be to have it take a pair of random access iterators and have it return an iterator pointing to the "max" element:
template <typename RandomAccessIt>
RandomAccessIt myMax (RandomAccessIt first, RandomAccessIt last)
first is an iterator to the first element in the range and last is an iterator to one-past-the-end of the range, as is idiomatic for the STL algorithms. Pointers are usable as random access iterators, so this function can be called as
int* pointerToMaxElement = myMax(arr, arr + arrSize);
The advantage of the iterator approach is that it works with any random access range, including an array, std::vector, std::array, and std::deque.
From a quick look, the two things that jump out at me are:
You're using T in different ways in the template function. You're returning a T object, and taking a reference to a T object as an argument - but when you use it, you're passing an an int array as the argument but expect just an int returned
You don't call your template function with any template (ie, myMax<int>(...)) Edit - as Mark B points out, this isn't required however