Barry
Barry

Reputation: 143

C++11 for loop in a Template Function

I am trying to write a function which would Print Data on the console. The function is to be templated as it should accept different types of Data.

The code is as shown below:

template<typename DataType>
void PrintData(DataType *X)
{
    for (DataType Data : X)
    {
        cout << Data << "\t";
    }
    cout << endl;
}

int main()
{

    int nArray[7] = { 7, 5, 4, 3, 9, 8, 6 };
    double dArray[5] = { 4.3, 2.5, -0.9, 100.2, 3.0 };

    PrintData(nArray);
    PrintData(dArray);

    system("pause");
    return EXIT_SUCCESS;
}

I get an error that variable Data is undeclared in the templated function PrintData.

error C2065: 'Data' : undeclared identifier 
error C3312: no callable 'begin' function found for type 'double *'    
error C3312: no callable 'begin' function found for type 'int *'    
error C3312: no callable 'end' function found for type 'double *'    
error C3312: no callable 'end' function found for type 'int *'  

Any help would be appreciated. Thanks

Upvotes: 3

Views: 1951

Answers (4)

user1
user1

Reputation: 4131

As Igor suggested, If at all you wish to use DataType * then you need to do something like this

#include <iostream>
#include <iterator>
using namespace std;

template <typename DataType, size_t N> 
void PrintData(DataType (&X)[N])
{
    for (auto i : X)
        cout << i << "\t";

    cout << endl;
}

int main()
{    
    int nArray[7] = { 7, 5, 4, 3, 9, 8, 6 };
    double dArray[5] = { 4.3, 2.5, -0.9, 100.2, 3.0 };

    PrintData(nArray);
    PrintData(dArray);

    return EXIT_SUCCESS;
}

Output

7   5   4   3   9   8   6   
4.3 2.5 -0.9    100.2   3   

Explanation:

If you see void PrintData(int* nArray); & void PrintData(int (&nArray)[7] ); are similar declarations, except that seconds one tells where array ends.

Template function

template <typename DataType, size_t N> 
void PrintData(DataType (&X)[N])

is deduced as'

void PrintData(int (&nArray)[7] )

You could also write

void PrintData(int (&nArray)[7] )
{
    for (auto i : nArray)
        cout << i << "\t";

    cout << endl;
}

Upvotes: 1

cqdjyy01234
cqdjyy01234

Reputation: 1190

Assuming you have included the iostream header file and the using namespace std; directive. Then your problems are:

  1. You should not use DataType *. Your code makes X a pointer, which is different from array. Use DataType const& or DataType&& instead.
  2. You have to include the iterator header file which provides the begin and end function for C-style array.

The following code works for me.

#include <iostream>
#include <iterator>
using namespace std;

template<typename DataType>
void PrintData(DataType const& X)
{
    for (auto Data : X)
    {
        cout << Data << "\t";
    }
    cout << endl;
}

int main()
{

    int nArray[7] = { 7, 5, 4, 3, 9, 8, 6 };
    double dArray[5] = { 4.3, 2.5, -0.9, 100.2, 3.0 };

    PrintData(nArray);
    PrintData(dArray);

    return EXIT_SUCCESS;
}

As commented by Igor Tandetnik, you may use template<struct DataType, size_t N> if you want to refer the size of the array.

Update:

  1. With template<struct DataType> and DataType *X, DataType is deduced as int and double, and X is a pointer which is not a container.
  2. With template<struct DataType, size_t N> and DataType (&X)[N], DataType is deduced as int and double, and X is an array which can be used with range-based for loop.
  3. With template<struct DataType> and DataType&& X or DataType const& X, DataType is deduced as int[7] or double[5], and X is an array as well.

Upvotes: 4

SashaMN
SashaMN

Reputation: 708

You have some problems:

1) DataType must be a container. So, try to use:

std::vector<int> nArray = { 7, 5, 4, 3, 9, 8, 6 };
std::vector<double> dArray = { 4.3, 2.5, -0.9, 100.2, 3.0 };

2) You are not going to change the container. It's better to pass container by const reference:

template<typename DataType>
void PrintData(const DataType & X);

3) Change the loop like this:

for (const auto & value : X) {
    std::cout << value << "\t";
}

Code example:

#include <iostream>
#include <vector>

template<typename DataType>
void PrintData(const DataType & X) {
    for (const auto & value : X) {
        std::cout << value << "\t";
    }
    std::cout << std::endl;
}

int main() {
    std::vector<int> nArray = { 7, 5, 4, 3, 9, 8, 6 };
    std::vector<double> dArray = { 4.3, 2.5, -0.9, 100.2, 3.0 };
    PrintData(nArray);
    PrintData(dArray);
    return 0;
}

Upvotes: 1

Ami Tavory
Ami Tavory

Reputation: 76391

The problem is that you're passing the name of the array (e.g., nArray), which is just a pointer to the first element, basically. However, new-style for loops expect something on which you can call begin and end - a range.

The following changes make it work by using a vector instead of an array. Note that there are very few differences otherwise, and, in general, very few reason to use C-style arrays in contemporary C++.

#include <iostream>                                                                                                                                                                                          
#include <vector>

using namespace std;

template<typename DataType>
void PrintData(const DataType &X)
{
    for (const auto &Data : X)
    {
        cout << Data << "\t";
    }
    cout << endl;
}

int main()
{

    vector<int> nArray = { 7, 5, 4, 3, 9, 8, 6 };
    vector<double> dArray = { 4.3, 2.5, -0.9, 100.2, 3.0 };

    PrintData(nArray);
    PrintData(dArray);

    system("pause");
    return EXIT_SUCCESS;

Upvotes: 2

Related Questions