Search code examples
c++classtemplatesc++17overloading

Function in class keeps returning errors (converting type void or Student to float, or directory not found)


I am trying to return the average of a sum of integers as a float. I am trying to keep everything in the header, and only call functions in main. However, calculateAverage keeps returning errors.

/tmp/ccmVBZhQ.o: In function `Student::calculateAverage()':                     
grade.cpp:(.text._ZN7Student16calculateAverageEv[_ZN7Student16calculateAverageEv
]+0x2f): undefined reference to `std::iterator_traits<__gnu_cxx::__normal_iterat
or<int*, std::vector<int, std::allocator<int> > > >::value_type reduce<__gnu_cxx
::__normal_iterator<int*, std::vector<int, std::allocator<int> > > >(__gnu_cxx::
__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__n
ormal_iterator<int*, std::vector<int, std::allocator<int> > >)'                 
collect2: error: ld returned 1 exit status                                      
./vpl_execution: line 22: ./a.out: No such file or directory                    

I have been trying to figure this out for over a week, and I need some help here. I am trying to set the float for 'average', but among other errors I have encountered, includes trying to convert the type Student or void to float.

#include <iostream>
#include <vector>
#include <string>
#include <numeric>
#include <functional>
using namespace std;
template< class InputIt >
typename std::iterator_traits<InputIt>::value_type
    reduce( InputIt first, InputIt last );
class College
{
    private:
        static string principal_name;  // principal_name is common for all the students
    public:
        static void setPrincipalName(string name)
        {
            principal_name = name;
        }
       static string getPrincipalName()
        {
            return principal_name;
        }
};
//Initialize the static principal_name variable with value "John" here

string College::principal_name = "John";


class Student
{
    private:
        vector<int> gradesVec;
        int id,stdId,markElement;
        string name,studentName,reqName;
        string return1 = "Student Name : ",return2 = "Student ID : ",return3 = "Principal Name : ",return4 = "Average : ",return5 = "Grade : ";
        string prompt1 = "Enter Student ID : ",prompt2 = "Enter Student Name : ",prompt3 = "Enter the five subject marks : ";
        float average;
        char grade;
        College cObj;
        float marks[5];
    public:
    
    void promptID()  {
        cout << prompt1 << endl;
    }
    void promptStdName() {
        cout << prompt2 << endl;
    }
    void promptMarks()  {
        cout << prompt3 << endl;
    }
    void nameRequest()  {
        cin >> studentName;
    }
    void idRequest()    {
        cin >> stdId;
    }
    void reqMarks() {
        cin >> markElement;
    }
    void setMarksVector()   {
        gradesVec.push_back(markElement);
    }
    void getNameRequest()   {
        
    }
    void getIdRequest() {
        
    }
    void getMarksVector()   {
        
    }
    void getStudentDetails();
    void calculateAverage() {
        average = (reduce(gradesVec.begin(),gradesVec.end())) / (gradesVec.size());

    };
    void findGrade()    {
        
    }
    void displayStudentDetails();
    void setId(int id)
    {
        this->id=id;
    }
    int getId()
    {
        return id;
    }
    void setAverage(float average)
    {
        this->average=average;
    }
    int getAverage()
    {
        return average;
    }
    void setName(string n)
    {
        this->name=n;
    }
    string getName()
    {
        return name;
    }
    void setMarks(float m[])
    {
        for(int i=0; i<4;i++)
            this->marks[i]=m[i];
    }
    float* getMarks()
    {
        return marks;
    }
    void setGrade(char g)
    {
        grade=g;
    }
    char getGrade()
    {
        return grade;
    }
    College getCollegeObject()
    {
        return cObj;
    }

};
int main()  //DO NOT change the 'main' signature
{
    //Fill code here



int stdId, grade2;
float grade1, avg;
string studentName,grade;

Student student;

student.promptID();
student.idRequest();
student.setId(stdId);
student.promptStdName();
student.nameRequest();
student.setName(studentName);
student.promptMarks();
student.reqMarks();
student.setMarksVector();
student.reqMarks();
student.setMarksVector();
student.reqMarks();
student.setMarksVector();
student.reqMarks();
student.setMarksVector();
student.reqMarks();
student.setMarksVector();
student.calculateAverage();


student.setId(stdId);
student.setName(studentName);



return 0;
}

Solution

  • The reason of the error that you are referring to is that the template function reduce():

    template< class InputIt >
    typename std::iterator_traits<InputIt>::value_type
        reduce( InputIt first, InputIt last );
    

    is not defined.

    It seems you mean:

    template< class InputIt >
    typename std::iterator_traits<InputIt>::value_type
    reduce( InputIt first, InputIt last )
    {
        return std::reduce( first, last );
    }
    

    And in the member function calculateAverage(), you need to use a qualified name to avoid ambiguity:

    void calculateAverage() {
        average = (::reduce(gradesVec.begin(),gradesVec.end())) / ( float )(gradesVec.size());
    }
    

    Here is a demonstration program:

    #include <iostream>
    #include <vector>
    #include <iterator>
    #include <numeric>
    
    template< class InputIt >
    typename std::iterator_traits<InputIt>::value_type
        reduce( InputIt first, InputIt last )
        {
            return std::reduce( first, last );
        }
    
    class Student
    {
    public:
        std::vector<int> gradesVec;
        float average;
        void calculateAverage() {
            average = (::reduce(gradesVec.begin(),gradesVec.end())) / ( float )(gradesVec.size());
    
        }
    };    
    
    int main()
    {
        Student student = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } };
        student.calculateAverage();
    
        std::cout << "student.average = " << student.average << '\n';
    }
     
    

    The program output is

    student.average = 5.5
    

    I think the template function ::reduce() is redundant. You could directly call the standard algorithm std::reduce() from the member function.