I'm having a function of finding max and I want to send static array via reference, Why isn't this possible?
template <class T>
T findMax(const T &arr, int size){...}
int main{
int arr[] = {1,2,3,4,5};
findMax(arr, 5); // I cannot send it this way, why?
return 0;
}
Use correct syntax. Change signature to:
template <class T, size_t size>
T findMax(const T (&arr)[size]){...}
Or you can use std::array argument for findMax() function.
Live Example
Why isn't this possible?
const T &arr: Here arr is a reference of type T and not the reference to array of type T as you might think. So you need [..] after arr. But then it will decay to a pointer.
Here you can change the binding with () and use const T (&arr)[SIZE].
For more, you can try to explore the difference between const T &arr[N] v/s const T (&arr)[N].
Related
(I can't seem to find a name for this paradigm, but you'll get a bonus upvote if you can!) This template paradigm is used to prevent an array from decaying into a pointer:
template <size_t N>
void foo(const char (&bar) [N]);
Live Example
We are able to use N in the body of foo to get the size off bar. Given const char array[] = "lorem ipsum" we use this call foo(array) to define bar as a const char (&) [12], effectively passing 2 parameters for the price of one.
I want to use this same idea but in a return, for example:
template <size_t N>
const char (&) [N] foo(const char (&bar) [N]);
Such that I could pass the array through, and have another reference to it, such as: auto result = foo(bar)
The code I have here yields the error:
unrecognizable template declaration/definition
Is this possible?
EDIT:
For clarification, I want to be able to have a function return that will result in the equivalent of:
auto& result = bar;
Such that result will be a const char (&) [*] where * is the size of bar.
C++ syntax is wonderful:
template <std::size_t N>
const char (&f(const char (&arr)[N]))[N] // take that, Lisp
{
return arr;
}
For the less masochistic:
template <std::size_t N> using CarrN = const char[N];
template <std::size_t N>
CarrN<N> & f(CarrN<N> & arr)
{
return arr;
}
As for terminology: We usually say that "arr is passed by reference", though the more discerning user might say "passed as an lvalue" (and also returned as such).
I don't know if it's possible but I'd like to do something like this:
template <typename T>
int search(T array, int first = 0, int last = array.size())
{
}
Here T should be a container and I'd like to know its size and use it as a default parameter. Is that possible?
Edit: yep, made a mistake its not T but array.
You can't use T.size() since T is not an object.
You can use function overloads to accomplish what you are trying.
template <typename T>
int search(T const& array, int first, int last)
{
}
template <typename T>
int search(T const& array, int first = 0)
{
return search(array, first, array.size());
}
PS I changed the type of the array to T const& from T. This will prevent making copies when the function(s) gets called.
It is not possible. Instead you should replace the last default parameter to normal parameter, and pass the size of container while calling the function, e.g.,
template <typename T>
int search(T array, int last, int first=0)
{
// you can also directly use array.size() here,
// so no need for extra parameter
}
vector<int> v;
v.push_back(1);
v.push_back(2);
// call search
search< vector<int> >(v, v.size());
I need process an array whose data-type is either float64_t or uint32_t. I want to make a function such that the pointer to the given array can be taken as a parameter to the function in this way:
void func_name(array_type* ptr_name, int count, data_type x)
//x can be float64_t or uint32_t
As you can see, beforehand I don't know the data-type of the pointer. How do I approach this problem in C++?
You can overload the functions:
void func(float64_t* ptr, int count);
void func(uint32_t* ptr, int count);
or make a function template:
template<typename T>
void func(T* ptr, int count);
The "data-type" (sic) of an array (and pointers) is a part of its type, you don't need to do anything special. Whichever approach you decide to take, the compiler will figure out for you which function to call (or what T will be when instantiating a template).
template<typename T>
void func(T* ptr, int count) { }
int main()
{
float f_arr[42] = {};
int i_arr[84] = {};
func(f_arr, 42); // instantiates func with T = float
func(i_arr, 84); // instantiates func with T = int
}
You can create a template - as already suggested by jrok
template<typename T>
void func(T* ptr, int count);
This way you will be able to pass a pointer to ANY data type to your function. Essentially a template a template expands into a function for each data type you use it with, at compile time.
if you however you want to over-complicate things, for obfuscation's sake let's say, you could do the following:
void func(void* ptr, int count);
have you function take a generic pointer- you will have to do a reinterpret cast when calling the function to convert your pointer to a void*, and inside the function to convert it to which ever pointer type you like; and your count will be the number of bytes you want to read.
But I'm sure you will appreciate the simplicity and transparency of the first solution ( the template).
I have a template method as follows:-
template<typename T, int length>
void ProcessArray(T array[length]) { ... }
And then I have code using the above method:-
int numbers[10] = { ... };
ProcessArray<int, 10>(numbers);
My question is why do I have to specify the template arguments explicitly. Can't it be auto-deduced so that I can use as follows:-
ProcessArray(numbers); // without all the explicit type specification ceremony
I am sure I am missing something basic! Spare a hammer!
You can't pass arrays by value. In a function parameter T array[length] is exactly the same as T* array. There is no length information available to be deduced.
If you want to take an array by value, you need something like std::array. Otherwise, you can take it by reference, which doesn't lose the size information:
template<typename T, int length>
void ProcessArray(T (&array)[length]) { ... }
You're missing the correct argument type: arrays can only be passed by reference:
template <typename T, unsigned int N>
void process_array(T (&arr)[N])
{
// arr[1] = 9;
}
double foo[12];
process_array(foo); // fine
This question already has answers here:
How does this template magic determine array parameter size?
(3 answers)
Closed 6 years ago.
template<typename T, size_t n>
size_t array_size(const T (&)[n])
{
return n;
}
The part that I don't get is the parameters for this template function. What happens with the array when I pass it through there that gives n as the number of elements in the array?
Well, first you have to understand that trying to get a value out of an array can give you a pointer to its first element:
int a[] = {1, 2, 3};
int *ap = a; // a pointer, size is lost
int (&ar)[3] = a; // a reference to the array, size is not lost
References refer to objects using their exact type or their base-class type. The key is that the template takes arrays by reference. Arrays (not references to them) as parameters do not exist in C++. If you give a parameter an array type, it will be a pointer instead. So using a reference is necessary when we want to know the size of the passed array. The size and the element type are automatically deduced, as is generally the case for function templates. The following template
template<typename T, size_t n>
size_t array_size(const T (&)[n]) {
return n;
}
Called with our previously defined array a will implicitly instantiate the following function:
size_t array_size(const int (&)[3]) {
return 3;
}
Which can be used like this:
size_t size_of_a = array_size(a);
There's a variation I made up some time ago [Edit: turns out someone already had that same idea here] which can determine a value at compile time. Instead of returning the value directly, it gives the template a return type depending on n:
template<typename T, size_t n>
char (& array_size(const T (&)[n]) )[n];
You say if the array has n elements, the return type is a reference to an array having size n and element type char. Now, you can get a compile-time determined size of the passed array:
size_t size_of_a = sizeof(array_size(a));
Because an array of char having n elements has sizeof n, that will give you the number of elements in the given array too. At compile time, so you can do
int havingSameSize[sizeof(array_size(a))];
Because the function never is actually called, it doesn't need to be defined, so it doesn't have a body. Hope I could clear the matter up a little bit.
Think of it this way, suppose you had a bunch of functions:
// Note that you don't need to name the array, since you don't
// actually reference the parameter at all.
size_t array_size(const int (&)[1])
{
return 1;
}
size_t array_size(const int (&)[2])
{
return 2;
}
size_t array_size(const int (&)[3])
{
return 3;
}
// etc...
Now when you call this, which function gets called?
int a[2];
array_size(a);
Now if you templatize the arraysize, you get:
template <int n>
size_t array_size(const int (&)[n])
{
return n;
}
The compiler will attempt to instantiate a version of array_size that matches whatever parameter you call it with. So if you call it with an array of 10 ints, it will instantiate array_size with n=10.
Next, just templatize the type, so you can call it with more than just int arrays:
template <typename T, int n>
size_t array_size(const T (&)[n])
{
return n;
}
And you're done.
Edit: A note about the (&)
The parentheses are needed around the & to differentiate between array of int references (illegal) and reference to array of ints (what you want). Since the precedence of [] is higher than &, if you have the declaration:
const int &a[1];
because of operator precedence, you end up with a one-element array of const references to int. If you want the & applied first, you need to force that with parentheses:
const int (&a)[1];
Now the you have a const reference to a one element array of ints. In the function parameter list, you don't need to specify the name of a parameter if you don't use it, so you can drop the name, but keep the parentheses:
size_t array_size(const int (&)[1])
Nothing happens to the array. It's an unused parameter that is used to resolve the signature of the template function.
It also cannot be used as a template argument, but that's a separate nit.
A little weird way to get the result as compile-time const for those of us who don't have "constexpr":
#include <iostream>
namespace
{
template <size_t V>
struct helper
{
enum
{
value = V
};
};
template<typename T, size_t Size>
auto get_size(T(&)[Size]) -> helper < Size >
{
return helper < Size >() ;
}
template<typename T>
struct get_value
{
enum
{
value = T::value
};
};
}
int main()
{
std::cout << get_value<decltype(get_size("Foo bar baz"))>::value;
}