Solved

Linking Errors...

Posted on 2004-09-28
4
194 Views
Last Modified: 2013-11-17
I have a data structure mathematical set class that I am using a template on and the code is as follows:

::sets.h::

#ifndef SETS_H
#define SETS_H

#include<iostream>

using namespace std;

template <class Type, int SetSize> class set_type {

            int count;
            Type EmptyElement;
            Type set[SetSize];
            
      public:

            set_type();
            
            void input_set();
            void print_set(ofstream&);
            
            bool is_empty();
            bool is_element(Type);
            
            set_type<Type, SetSize> operator+ (const set_type<Type, SetSize>&) const;
            set_type<Type, SetSize> operator* (const set_type<Type, SetSize>&) const;
            set_type<Type, SetSize> operator- (const set_type<Type, SetSize>&) const;

};

#endif

::sets.cpp::

#include "sets.h"
#include <fstream>

using namespace std;

template <class Type, int SetSize> set_type<Type, SetSize>::set_type()
{

      for(int lcv = 0; lcv < SetSize; lcv++)
      {

            set[lcv] = false;

            count = 0

            EmptyElement = '0'

      }

}

template <class Type, int SetSize> void set_type<Type, SetSize>::input_set()
{

      Type NewElement;
      
      count = 0;

      cout << "Enter elements, finish with " << EmptyElement << endl;
      cout << endl;
      cout << "Element 1: ";

      cin >> NewElement;

      for(int lcv = 0; lcv < SetSize && NewElement != EmptyElement; lcv++)
      {

            if (contains(NewElement)) {
                        
                  cout << "Element already in set!" << endl;

                  --lcv;

            }
            
            else
            {
                        
                        set[ele - 'a'] = true;
                        
            }

            if (lcv < SetSize - 1) {

                  cout << "Element " << (lcv + 2) << ": ";
                  cin >> NewElement;

            }

      }

}

template <class Type, int SetSize> void set_type<Type, SetSize>::print_set(ofstream &fout)
{
      
      bool first = true;      // flag to determine output format if first element
      
      fout << '{';
      
      if(!is_empty())            // If the set is empty, nothing to print
      {
      
            for(int lcv = 0; lcv < 26; lcv++)      // loop through all elements
            {

                  if(set[lcv] && !first)      // if an element is true and not the first
                  {                                    // printed

                        fout << ", " << (char)('a' + lcv);      // print comma, space, ele.

                  }
                  
                  else if(set[lcv] && first)      // if ele. T and 1st printed
                  {

                        fout << (char)('a' + lcv);      // output element

                        first = false;      // set first printed flag to false

                  }

            }

      }
      
      fout << '}';
      
      return;
}

template <class Type, int SetSize> bool set_type<Type, SetSize>::is_empty()
{
      
      for(int lcv = 0; lcv < 26; lcv++)
      {
      
            if(set[lcv])
            {
                  
                  return false;

            }

      }

      return true;
}

template <class Type, int SetSize> bool set_type<Type, SetSize>::is_element(Type ele)
{
      
      if(set[ele - 1])
      {

            return true;

      }
      
      return false;

}

template <class Type, int SetSize> set_type<Type, SetSize> set_type<Type, SetSize>::operator+ (const set_type<Type, SetSize>& set2) const
{
      
      if(is_empty())      // if the first set is empty, result of the OR will be set2
      {
            
            return set2;

      }
      
      set_type <Type, SetSize> set3;      // set of results
      
      for(int lcv = 0; lcv < SetSize; lcv++)      // for loop to compare every element
      {
      
            if(set[lcv] || set2.is_element(1 + lcv))
            {

                  set3.set[lcv] = true;

            }

      }
      
      return set3;      // return the newly constructed set
}

template <class Type, int SetSize> set_type<Type,SetSize> set_type<Type, SetSize>::operator* (const set_type<Type, SetSize>& set2) const
{

      if(is_empty())            // if the 1st set is empty, no elements in the result
      {
      
            return *this;      //will be true...return the empty set

      }
      
      set<Type, SetSize> set3;
      
      for(int lcv = 0; lcv < SetSize; lcv++)      // for loop to compare every element
      {

            if(set[lcv] && set2.is_element(1 + lcv))
            {

                  set3.set[lcv] = true;

            }

      }
      
      return set3;      // return the newly constructed set

}

template <class Type, int SetSize> set_type<Type,SetSize> set_type<Type, SetSize>::operator- (const set_type<Type, SetSize>& set2) const
{
      if(set2.is_empty())      // if the second set is empty, the result is the first
      {
            
            return *this;      // set

      }
      
      set<Type, SetSize> set3;
      
      for(int lcv = 0; lcv < SetSize; lcv++)      // for loop to compare every element
      {
            
            if(set[lcv] && !set2.is_element(1 + lcv))
            {

                  set3.set[lcv] = true;

            }

      }
      
      return set3;      // return the newly constructed set

}

::main.cpp::


#include <iostream>
#include <fstream>

using namespace std;

#include "sets.h"

int main()
{
      char ele;
      set_type<char, 100> set_one, set_two, set_three;
      ofstream fout ("output.txt");      // open an output file object called fout

      cout << "Setting values for Set One..." << endl;
      set_one.input_set();
      fout << endl << endl << "Set One is..." << endl << endl;
      set_one.print_set(fout);
      fout << endl;

      cout << "Setting values for Set Two..." << endl;
      set_two.input_set();
      fout << endl << endl << "Set Two is..." << endl << endl;
      set_two.print_set(fout);
      fout << endl;

      set_one.print_set(fout);      
      if (set_one.is_empty())
            fout << " is an empty set" << endl << endl;
      else
            fout << " is not an empty set" << endl << endl;

      cout << "Enter the letter reference to check the status of an element in Set One: ";
      cin.get(ele);      // get one char from input stream
      cin.ignore();      // ignore the rest of the stream
      fout << ele;
      if (set_one.is_element(ele)) fout << " is an element of ";
      else fout << " is not an element of ";
      set_one.print_set(fout);
      fout << endl;

      set_three = set_one + set_two;
      fout << endl << "The union of ";
      set_one.print_set(fout);      
      fout << " and ";
      set_two.print_set(fout);
      fout << " is ";
      set_three.print_set(fout);
      fout << endl;

      set_three = set_one * set_two;
      fout << endl << "The intersection of ";
      set_one.print_set(fout);      
      fout << " and ";      
      set_two.print_set(fout);
      fout << " is ";
      set_three.print_set(fout);
      fout << endl;

      set_three = set_one - set_two;
      fout << endl << "The difference of ";
      set_one.print_set(fout);      
      fout << " and ";      
      set_two.print_set(fout);
      fout << " is ";
      set_three.print_set(fout);
      fout << endl;

      fout.close();      // close the output file

      return 0;
}

The errors that I keep getting are linking errors which are usually when an interface doesn't match up to an implementation, however I can't seem to find anything wrong with it unless I'm just not using it correctly.  If anyone has some advice please feel free to share, I've given alot of points on this one due to I've spent hours looking at the same thing, Good Luck!!

Here are the errors by the way:

sets error LNK2001: unresolved external symbol "public: class set_type<char,100> __thiscall set_type<char,100>::operator-(class set_type<char,100> const &)const " (??G?$set_type@D$0GE@@@$$FQBE?AV0@ABV0@@Z)

sets error LNK2001: unresolved external symbol "public: class set_type<char,100> __thiscall set_type<char,100>::operator*(class set_type<char,100> const &)const " (??D?$set_type@D$0GE@@@$$FQBE?AV0@ABV0@@Z)

sets error LNK2001: unresolved external symbol "public: class set_type<char,100> __thiscall set_type<char,100>::operator+(class
set_type<char,100> const &)const " (??H?$set_type@D$0GE@@@$$FQBE?AV0@ABV0@@Z)

sets error LNK2001: unresolved external symbol "public: bool __thiscall set_type<char,100>::is_element(char)" (?is_element@?$set_type@D$0GE@@@$$FQAE_ND@Z)

sets error LNK2001: unresolved external symbol "public: bool __thiscall set_type<char,100>::is_empty(void)" (?is_empty@?$set_type@D$0GE@@@$$FQAE_NXZ)

sets error LNK2001: unresolved external symbol "public: void __thiscall set_type<char,100>::print_set(class std::basic_ofstream<char,struct std::char_traits<char> > &)" (?print_set@?$set_type@D$0GE@@@$$FQAEXAAV?$basic_ofstream@DU?$char_traits@D@std@@@std@@@Z)

sets error LNK2001: unresolved external symbol "public: void __thiscall set_type<char,100>::input_set(void)" (?input_set@?$set_type@D$0GE@@@$$FQAEXXZ)

sets error LNK2001: unresolved external symbol "public: __thiscall set_type<char,100>::set_type<char,100>(void)" (??0?$set_type@D$0GE@@@$$FQAE@XZ)

0
Comment
Question by:IceFuzsion
4 Comments
 
LVL 12

Accepted Solution

by:
andrewjb earned 125 total points
ID: 12167331
Put the implementation of the template functions into the .h file. Sometimes you're allowed a separate .cpp for templates, sometimes not - depends upon the compiler.

So the .h will be like...

<Lots of stuff...>

template <class Type, int SetSize> class set_type {

          int count;
          Type EmptyElement;
          Type set[SetSize];
         
     public:

        <Some functions..>
         
          bool is_empty() { if.... etc.};
     <Other stuff>

};


etc.
0
 
LVL 13

Assisted Solution

by:SteH
SteH earned 125 total points
ID: 12167400
It should be difficult to allow the separation of declaration and implementation of templates to different files: When the templated gets instantiated the types are specified and actual code is generated. But the implementation of the template can't be compiled nor linked since the types are missing. And C++ should do type checking. So for separating it to two files you need to include both to the file using it and the implementation file should not get compiled, otherwise you get linking errors. That way to allow normal handling of endings the implementation has to be in a .h(pp) file as well and a separation of two headers doesn't really make sense.
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Programmer's Notepad is, one of the best free text editing tools available, simply because the developers appear to have second-guessed every weird problem or issue a programmer is likely to run into. One of these problems is selecting and deleti…
Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn how to use and create keystrokes in Netbeans IDE 8.0 for Windows.

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

24 Experts available now in Live!

Get 1:1 Help Now