0

the code isn't working and I'm not sure where I've gone wrong any help would be much appreciated this is the details of the assignment create a class template by writing a template for a class named "Pair". This class will represent a pair of data members of a type that is parameterized in the template definition. For example, you could have a Pair of integers, a Pair of doubles, etc.

/* so I'm trying to implement this driver this is the driver.cpp file and
 * I'm trying to do it with a template class */

int main()
{
   Pair<char> letters('a', 'd');
   cout << "\nThe first letter is: " << letters.getFirst();
   cout << "\nThe second letter is: " << letters.getSecond();

   cout << endl;
   cin.get();
}

//this is my .h file code
template <class T>
class Pair
{
   private:
      T first;
      T second;
   public:
      Pair(const T, const T);
      T getFirst();
      T getSecond();
};

//this is my Pair.cpp
#include "Pair.h"


template<class T>
Pair<T>::Pair(const T first, const T second)
{
   return first, second;
}

template<class T>
inline T Pair<T>::getFirst()
{
   return first;
}

template<class T>
inline T Pair<T>::getSecond()
{
   return second;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
Alycia
  • 11
  • 1
  • 3
  • The constructor should not return the values, but set the member variables to the parameter values. A bit tricky when you use the same names... – Bo Persson Apr 22 '17 at 22:41
  • *the code isn't working* doesn't explain much. Are you seeing problems at compile time, run time? What's the nature of the problem? Post messages from compiler if there is a compile time problem. Post the output if there is a run time problem. – R Sahu Apr 22 '17 at 22:47
  • Off topic: recommend a read of [Why include guards?](http://stackoverflow.com/questions/21090041/why-include-guards) – user4581301 Apr 22 '17 at 23:01
  • I'm getting three errors that say unresolved external symbol – Alycia Apr 23 '17 at 02:27

3 Answers3

1

There are two distinct problems with you code.

First, you only have the declaration of the member functions in Pair.h and the definitions in a seperate Pair.cpp file. While this works for regular functions, it doesn't work for templates (see Why can templates only be implemented in the header file?), as mentioned already by Guillaume Racicot in a comment to your question.

The second issue is that your constructor isn't initializing the data members of yourPair class, but instead returns the second argument you passed to it, even though a constructor can't have a return value.

To fix this you need to change the definition of the constructor to

template <typename T>
Pair<T>::Pair(T fst, T snd)
    : first{std::move(fst)},
      second{std::move(snd)} {
}

The calls to std::move are not necessary here, but this is the idiomatic way to move values into variables. If you were to only do first{fst} you'd end up making one additional copy instead of a move, which isn't that big of a deal for primitive types such as int or float, but if you were to create a pair of large objects (e.g. two 1000 element vectors) then this can make a huge difference.

After applying both these changes and adding include guards you should end up with a single Pair.h file

#ifndef PAIR_H
#define PAIR_H

template <class T>
class Pair
{
   private:
      T first;
      T second;
   public:
      Pair(T, T);
      T getFirst();
      T getSecond();
};

template<class T>
Pair<T>::Pair(T fst, T snd)
    : first{std::move(fst)},
      second{std::move(snd)}
{
}

template<class T>
T Pair<T>::getFirst()
{
   return first;
}

template<class T>
T Pair<T>::getSecond()
{
   return second;
}
#endif
Community
  • 1
  • 1
Corristo
  • 4,911
  • 1
  • 20
  • 36
-1

here is simple pair.h template

// Pair.h
// template for a pair of items of arbitrary types

#include <sstream>
using namespace std;

template <typename S, typename T>
class Pair
   {
      public:
               Pair();
               Pair(S,T);
               Pair(Pair &);
               ~Pair();
               const Pair &operator=(const Pair &other);

               string toString();

               S* getFirst();
               T* getSecond();
              int getPairCount();

               void setFirst(S);
               void setSecond(T);

      private:
               S *f;
               T *s;
               static int count;

   };

template <typename S, typename T>
int Pair<S,T>::count=0;

// 0-parameter constructor
template <typename S, typename T>
Pair<S,T>::Pair()
   {
      f = NULL;
      s = NULL;
      count++;
   }

// 2-param constructor
template <typename S, typename T>
Pair<S,T>::Pair(S x, T y)
   {
      f = new S;  *f = x;
      s = new T;  *s = y;
      count++;
   }


// get first element in pointer
template <typename S, typename T>
S* Pair<S,T>::getFirst()
   {
      if (f!=NULL)
         {  S *tmp = new S;
            *tmp = *f;
            return tmp;
         }
      else
         return NULL;
   }

// get second element in pointer
template <typename S, typename T>
T* Pair<S,T>::getSecond()
   {
      if (s!=NULL)
         {
            T *tmp = new T;
            *tmp = *s;
            return tmp;
         }
      else
         return NULL;
   }

// set first element
template <typename S, typename T>
void Pair<S,T>::setFirst(S x)
   {
      if (f==NULL)
         f = new S;
      *f = x;
   }

// set second element
template <typename S, typename T>
void Pair<S,T>::setSecond(T y)
   {
      if (s==NULL)
         s = new T;
      *s = y;
   }

// make a string representation
template <typename S, typename T>
string Pair<S,T>::toString()
   {
      stringstream ss;
      ss<<"(";
      if (f==NULL)
         ss<<"NULL";
      else
         ss<<(*f);
      ss<<",";
      if (s==NULL)
         ss<<"NULL";
      else
         ss<<(*s);
      ss<<")";
      return ss.str();
   }

// keep count
template <typename S, typename T>
int Pair<S,T>::getPairCount(){
    return count;}

//copy constructor
template <typename S, typename T>
Pair<S,T>::Pair(Pair &other)
{
f = NULL; s = NULL;
    if(other.f != NULL)
    f = new S(*other.f);

    if(other.s != NULL)
    s = new T(*other.s);

    count++;
}
//destructor

template <typename S, typename T>
Pair<S,T>::~Pair()
{
    if(f != NULL)
    delete f;

    if(s != NULL)
    delete s;

    f = NULL;
    s = NULL;

    count--;
}

//deep assignment

template <typename S, typename T>
const Pair<S,T> & Pair<S,T>::operator=(const Pair<S,T> &other)
{
    if(this != &other)
    {
        if(f != NULL)
        delete f;

        if(s != NULL)
        delete s;

        f = NULL; s = NULL;

        if(other.f != NULL)
        f = new S(*other.f);

        if(other.s != NULL)
        s = new T(*other.s);
    }
    return *this;
}
BlooB
  • 955
  • 10
  • 23
  • 3
    Eww, pointers... – aschepler Apr 23 '17 at 00:20
  • LOL, if you are working with templates you should have an idea over pointers. try reading the code, it will make sense – BlooB Apr 23 '17 at 00:23
  • Pointers are just uncalled for in this situation. If you really want those semantics, you should at least use `std::unique_ptr` or `std::optional` (C++17). – aschepler Apr 23 '17 at 00:24
  • @aschepler i simply pasted a header file that i had at hand as reference for her, i also believe she is doing this for a class and if tats a case i believe she should work with a simple good old pointer before learning different options that are there – BlooB Apr 23 '17 at 00:28
  • 1
    @dirty_feri Why not work with simple good old values before learning about owning raw pointers? – Guillaume Racicot Apr 23 '17 at 00:35
  • 1
    You make it sound like `std::unique_ptr` is an advanced topic. But in modern C++, using `new` and `delete` is an advanced topic, and to be avoided. – aschepler Apr 23 '17 at 00:40
  • To answer both comments, to be honest this is how i was taught and what i am use to, you guys are also correct – BlooB Apr 23 '17 at 00:46
  • I received a down vote for an answer that works and acomplishes the intended job, however no one else has introduced an answer – BlooB Apr 23 '17 at 04:49
  • @dirty_feri I downvoted this answer for many reasons, the main one was already stated in the comments: Use of owning raw pointers. Alycia stated she is doing this as part of an assignment, so presumably is still learning C++. As stated by aschepler, `new` and `delete` are not something a beginner should deal with, and you agreed with that sentiment. I feel we as a community shouldn't teach others things that are now considered bad practice, there already are enough bad tutorials out there. I recommend watching Kate Gregorys talk [Stop teaching C](https://www.youtube.com/watch?v=YnWhqhNdYyk). – Corristo Apr 23 '17 at 12:16
  • The second issue is that you completely ignored the code that was posted by Alycia. There are two simple fixes to the code in the question that make it work: Move the definitions to the header file and fix the constructor. Instead you provided a completely different implementation that doesn't even fit the requirements - the question states that `Pair` should implement a homogeneous pair, not a heterogeneous one. – Corristo Apr 23 '17 at 12:22
-1

The constructor should not return anything. Its function is to initialize the object by means of the variables passed as parameters.

template<class T>
Pair<T>::Pair(const T fst, const T scd) : first(fst), second(scd)
{}
Mario Rodríguez
  • 149
  • 1
  • 1
  • 7