Reputation: 716
I have here this code.
#include <iostream>
using namespace std;
template <typename T> inline T bigArry(const T data[5])
{
T level = data[0];
for(T item : data) // error C2143: syntax error : missing ',' before ':' (1st)
{ //error C2143: syntax error : missing ';' before '{' (3rd)
if(level<item){ level=item; }
}
return level;
}
int main()
{
int data[5]={//five variables}
cout << bigArry(data);//see reference to function template instantiation 'T bigArry<int>(const T [])' being compiled with [ T=int] (2nd)
return 0;
}
The function bigArry() returns the highest value out of a array of 5 elements.
The problem is that when I use the range-based loop it gives me the errors mentioned in the code. But when I use the usual for, everything goes back to normal. I mean, the syntax to me looks fine, I can't see the problem. I'm using Visual Studio 2010.
The other thing I want to ask is about the inline functions. Currently I'm reading C++ Primer Plus 6th edition. When do I know when a function is too big to be inlined? Is there a standard of how short the code should be? Or, do we use the inline functions when we "think" it's okay?
Upvotes: 6
Views: 807
Reputation: 361692
The parameter data
is NOT an array in your function template. It is actually a pointer.
This function
template <typename T> inline T bigArry(const T data[5])
is exactly same as this:
template <typename T> inline T bigArry(const T *data)
There is NO difference at all.
That is the reason why your code gives compilation error.
There're couple of fixes here:
You could accept the argument by reference, as:
template <typename T>
inline T bigArry(const T (&data)[5]) //NOTE &
That should work. But then that looks cumbersome. Maybe, use the next.
Or you could use this (as suggested by @yzt):
template <typename C>
inline auto bigArry(C const & data) -> decltype(data[0])
This is clean as well as more flexible than the above one (and the below one). In addition to passing arrays, you could pass any container as long as data[0]
is well-defined and means what it supposed to mean.
Or if you wish, you could use std::array<T, 5>
as:
template <typename T>
inline T bigArry(const std::array<T,5> & data)
Hope that helps.
Upvotes: 7
Reputation: 126522
That is because array types decay to pointers when used as function parameters or when passed as function argument. In other words, your function signature is equivalent to:
template <typename T> inline T bigArry(const T* data)
The range-based for
loop passes data
to the global std::begin()
and std::end()
functions in order to get iterators to (respectively) the first and the one-past-the-last element of the container.
Of course, there are no global std::begin()
and std::end()
functions that accept a pointer, and they couldn't be meaningfully defined either: how to determine the end of the container given just a pointer to its first element?
You can use std::array
instead of C arrays (std::array
is a zero-overhead wrapper around a C array), and modify your calling function accordingly:
template <typename T> inline T bigArry(std::array<T, 5> data)
// ^^^^^^^^^^^^^^^^
{
T level = data[0];
for(T item : data)
{
if(level<item){ level=item; }
}
return level;
}
int main()
{
std::array<int, 5> data = {1,2,3,4,5};
// ^^^^^^^^^^^^^^^^^^^^^^^
std::cout << bigArry(data);
return 0;
}
Here is a live example.
Upvotes: 6