4

this code produces 17 error C2995: function template has already been defined; there was a separate set of errors before adding the #include "set.h" header. There is a private .cpp and .h files associated with this.

/*
 * File: private/set.cpp
 * Last modified on Thu Jun 11 09:34:08 2009 by eroberts
 * -----------------------------------------------------
 * This file contains the implementation of the set.h interface.
 * Because of the way C++ compiles templates, this code must be
 * available to the compiler when it reads the header file.
 */

//#ifdef _set_h //original code

#ifndef _set_h
#define _set_h


#include "stdafx.h"

#include "set.h"

using namespace std;

template <typename ElemType>
Set<ElemType>::Set(int (*cmp)(ElemType, ElemType)) : bst(cmp) {
    cmpFn = cmp;
}

template <typename ElemType>
Set<ElemType>::~Set() {
    /* Empty */
}

template <typename ElemType>
int Set<ElemType>::size() {
    return bst.size();
}

template <typename ElemType>
bool Set<ElemType>::isEmpty() {
    return bst.isEmpty();
}

template <typename ElemType>
void Set<ElemType>::add(ElemType element) {
    bst.add(element);
}

template <typename ElemType>
void Set<ElemType>::remove(ElemType element) {
    bst.remove(element);
}

template <typename ElemType>
bool Set<ElemType>::contains(ElemType element) {
    return find(element) != NULL;
}

template <typename ElemType>
ElemType *Set<ElemType>::find(ElemType element) {
    return bst.find(element);
}

template <typename ElemType>
void Set<ElemType>::clear() {
    bst.clear();
}

/*
 * Implementation notes: Set operations
 * ------------------------------------
 * The code for equals, isSubsetOf, unionWith, intersectWith, and subtract
 * is similar in structure.  Each one uses an iterator to walk over
 * one (or both) sets, doing add/remove/comparision.
 */

template <typename ElemType>
bool Set<ElemType>::equals(Set & otherSet) {
    if (cmpFn != otherSet.cmpFn) {
        Error("Equals: sets have different comparison functions");
    }
    Iterator thisItr = iterator(), otherItr = otherSet.iterator();
    while (thisItr.hasNext() && otherItr.hasNext()) {
        if (cmpFn(thisItr.next(), otherItr.next()) != 0) return false;
    }
    return !thisItr.hasNext() && !otherItr.hasNext();
}

template <typename ElemType>
bool Set<ElemType>::isSubsetOf(Set & otherSet) {
    if (cmpFn != otherSet.cmpFn) {
        Error("isSubsetOf: sets have different comparison functions");
    }
    Iterator iter = iterator();
    while (iter.hasNext()) {
        if (!otherSet.contains(iter.next())) return false;
    }
    return true;
}

template <typename ElemType>
void Set<ElemType>::unionWith(Set & otherSet) {
    if (cmpFn != otherSet.cmpFn) {
        Error("unionWith: sets have different comparison functions");
    }
    Iterator iter = otherSet.iterator();
    while (iter.hasNext()) {
        add(iter.next());
    }
}

/*
 * Implementation notes: intersectWith
 * -----------------------------------
 * The most obvious way to write this method (iterating over
 * one set and deleting members that are not in the second)
 * fails because you can't change the contents of a collection
 * over which you're iterating.  This code puts the elements
 * to be deleted in a vector and then deletes those.
 */

template <typename ElemType>
void Set<ElemType>::intersectWith(Set & otherSet) {
    if (cmpFn != otherSet.cmpFn) {
        Error("intersectWith:"
              " sets have different comparison functions");
    }
    Iterator iter = iterator();
    Vector<ElemType> toDelete;
    while (iter.hasNext()) {
        ElemType elem = iter.next();
        if (!otherSet.contains(elem)) toDelete.add(elem);
    }
    for (int i = 0; i < toDelete.size(); i++) {
        remove(toDelete[i]);
    }
}

template <typename ElemType>
void Set<ElemType>::intersect(Set & otherSet) {
    if (cmpFn != otherSet.cmpFn) {
        Error("intersect: sets have different comparison functions");
    }
    intersectWith(otherSet);
}

template <typename ElemType>
void Set<ElemType>::subtract(Set & otherSet) {
    if (cmpFn != otherSet.cmpFn) {
        Error("subtract: sets have different comparison functions");
    }
    Iterator iter = otherSet.iterator();
    while (iter.hasNext()) {
        remove(iter.next());
    }
}

template <typename ElemType>
void Set<ElemType>::mapAll(void (*fn)(ElemType)) {
    bst.mapAll(fn);
}

template <typename ElemType>
template <typename ClientDataType>
void Set<ElemType>::mapAll(void (*fn)(ElemType, ClientDataType &),
                           ClientDataType & data) {
    bst.mapAll(fn, data);
}

/*
 * Set::Iterator class implementation
 * ----------------------------------
 * The Iterator for Set relies on the underlying implementation of the
 * Iterator for the BST class.
 */

template <typename ElemType>
Set<ElemType>::Iterator::Iterator() {
    /* Empty */
}

template <typename ElemType>
typename Set<ElemType>::Iterator Set<ElemType>::iterator() {
    return Iterator(this);
}

template <typename ElemType>
Set<ElemType>::Iterator::Iterator(Set *setptr) {
    iterator = setptr->bst.iterator();
}

template <typename ElemType>
bool Set<ElemType>::Iterator::hasNext() {
    return iterator.hasNext();
}

template <typename ElemType>
ElemType Set<ElemType>::Iterator::next() {
    return iterator.next();
}

template <typename ElemType>
ElemType Set<ElemType>::foreachHook(FE_State & fe) {
    if (fe.state == 0) fe.iter = new Iterator(this);
    if (((Iterator *) fe.iter)->hasNext()) {
        fe.state = 1;
        return ((Iterator *) fe.iter)->next();
    } else {
        fe.state = 2;
        return ElemType();
    }
}



#endif

the header file

/*
 * File: set.h
 * Last modified on Thu Jun 11 09:17:43 2009 by eroberts
 *      modified on Tue Jan  2 14:34:06 2007 by zelenski
 * -----------------------------------------------------
 * This interface file contains the Set class template, a
 * collection for efficiently storing a set of distinct elements.
 */

#ifndef _set_h
#define _set_h

#include "cmpfn.h"
#include "bst.h"
#include "vector.h"
#include "foreach.h"


/*
 * Class: Set
 * ----------
 * This interface defines a class template that stores a collection of
 * distinct elements, using a sorted relation on the elements to
 * provide efficient managaement of the collection.
 * For maximum generality, the Set is supplied as a class template.
 * The element type is determined by the client. The client configures
 * the set to hold values of a specific type, e.g. Set<int> or
 * Set<studentT>. The one requirement on the element type is that the
 * client must supply a comparison function that compares two elements
 * (or be willing to use the default comparison function that uses
 * the built-on operators  < and ==).
 */

template <typename ElemType>
class Set {

public:

/* Forward references */
    class Iterator;

/*
 * Constructor: Set
 * Usage: Set<int> set;
 *        Set<student> students(CompareStudentsById);
 *        Set<string> *sp = new Set<string>;
 * -----------------------------------------
 * The constructor initializes an empty set. The optional
 * argument is a function pointer that is applied to
 * two elements to determine their relative ordering. The
 * comparison function should return 0 if the two elements
 * are equal, a negative result if first is "less than" second,
 * and a positive resut if first is "greater than" second. If
 * no argument is supplied, the OperatorCmp template is used as
 * a default, which applies the bulit-in < and == to the
 * elements to determine ordering.
 */
    Set(int (*cmpFn)(ElemType, ElemType) = OperatorCmp);

/*
 * Destructor: ~Set
 * Usage: delete sp;
 * -----------------
 * The destructor deallocates  storage associated with set.
 */
    ~Set();

/*
 * Method: size
 * Usage: count = set.size();
 * --------------------------
 * This method returns the number of elements in this set.
 */
    int size();

/*
 * Method: isEmpty
 * Usage: if (set.isEmpty())...
 * ----------------------------
 * This method returns true if this set contains no
 * elements, false otherwise.
 */
    bool isEmpty();

/*
 * Method: add
 * Usage: set.add(value);
 * ----------------------
 * This method adds an element to this set. If the
 * value was already contained in the set, the existing entry is
 * overwritten by the new copy, and the set's size is unchanged.
 * Otherwise, the value is added and set's size increases by one.
 */
    void add(ElemType elem);

/*
 * Method: remove
 * Usage: set.remove(value);
 * -----------------------
 * This method removes an element from this set. If the
 * element was not contained in the set, the set is unchanged.
 * Otherwise, the element is removed and the set's size decreases
 * by one.
 */
    void remove(ElemType elem);

/*
 * Method: contains
 * Usage: if (set.contains(value))...
 * -----------------------------------
 * Returns true if the element in this set, false otherwise.
 */
    bool contains(ElemType elem);

/*
 * Method: find
 * Usage: eptr = set.find(elem);
 * -----------------------------
 * If the element is contained in this set, returns a pointer
 * to that elem.  The pointer allows you to update that element
 * in place. If element is not contained in this set, NULL is
 * returned.
 */
    ElemType *find(ElemType elem);

/*
 * Method: equals
 * Usage: if (set.equals(set2)) . . .
 * -----------------------------------
 * This predicate function implements the equality relation
 * on sets.  It returns true if this set and set2 contain
 * exactly the same elements, false otherwise.
 */
    bool equals(Set & otherSet);

/*
 * Method: isSubsetOf
 * Usage: if (set.isSubsetOf(set2)) . . .
 * --------------------------------------
 * This predicate function implements the subset relation
 * on sets.  It returns true if all of the elements in this
 * set are contained in set2.  The set2 does not have to
 * be a proper subset (that is, it may be equals).
 */
    bool isSubsetOf(Set & otherSet);

/*
 * Methods: unionWith, intersectWith, subtract
 * Usage: set.unionWith(set2);
 *        set.intersectWith(set2);
 *        set.subtract(set2);
 * -------------------------------
 * These fmember unctions modify the receiver set as follows:
 *
 * set.unionWith(set2);      Adds all elements from set2 to this set.
 * set.intersectWith(set2);  Removes any element not in set2 from this set.
 * set.subtract(set2);       Removes all element in set2 from this set.
 */
    void unionWith(Set & otherSet);
    void intersectWith(Set & otherSet);
    void subtract(Set & otherSet);

/*
 * Method: clear
 * Usage: set.clear();
 * -------------------
 * This method removes all elements from this set. The
 * set is made empty and will have size() = 0 after being cleared.
 */
    void clear();

/*
 * SPECIAL NOTE: mapping/iteration support
 * ---------------------------------------
 * The set supports both a mapping operation and an iterator which
 * allow the client access to all elements one by one.  In general,
 * these  are intended for _viewing_ elements and can behave
 * unpredictably if you attempt to modify the set's contents during
 * mapping/iteration.
 */

/*
 * Method: mapAll
 * Usage: set.mapAll(Print);
 * -------------------------
 * This method iterates through this set's contents
 * and calls the function fn once for each element.
 */
    void mapAll(void (*fn)(ElemType elem));

/*
 * Method: mapAll
 * Usage: set.mapAll(PrintToFile, outputStream);
 * --------------------------------------------
 * This method iterates through this set's contents
 * and calls the function fn once for each element, passing
 * the element and the client's data. That data can be of whatever
 * type is needed for the client's callback.
 */
    template <typename ClientDataType>
    void mapAll(void (*fn)(ElemType elem, ClientDataType & data),
                ClientDataType & data);

/*
 * Method: iterator
 * Usage: iter = set.iterator();
 * -----------------------------
 * This method creates an iterator that allows the client to
 * iterate through the elements in this set.  The elements are
 * returned in the order determined by the comparison function.
 *
 * The idiomatic code for accessing elements using an iterator is
 * to create the iterator from the collection and then enter a loop
 * that calls next() while hasNext() is true, like this:
 *
 *     Set<int>::Iterator iter = set.iterator();
 *     while (iter.hasNext()) {
 *         int value = iter.next();
 *         . . .
 *     }
 *
 * This pattern can be abbreviated to the following more readable form:
 *
 *     foreach (int value in set) {
 *         . . .
 *     }
 *
 * To avoid exposing the details of the class, the definition of the
 * Iterator class itself appears in the private/set.h file.
 */
    Iterator iterator();

private:

#include "private/set.h"

};

#include "private/set.cpp"

#endif

Where is this going wrong

forest.peterson
  • 755
  • 2
  • 13
  • 30
  • 3
    Click on the tick mark below the upvote/downvote arrows. – dirkgently Jun 19 '12 at 04:28
  • they should reconsider the user interface - I never saw that tick mark and was looking for it. I was clicking on some other thing by the comments – forest.peterson Jun 19 '12 at 04:40
  • 2
    You can always post your suggestions on [meta](http://meta.stackoverflow.com/). – dirkgently Jun 19 '12 at 04:44
  • You should read [sscce.org](http://sscce.org/). All I see is a code dump and an error with no way of compiling the code myself. However, you can't separate the definitions of a template class and put them in a separate .cpp file ([reference](http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12)), so that is probably your problem. – Jesse Good Jun 19 '12 at 05:00

1 Answers1

9

The problem is circular dependency. set.h includes set.cpp and set.cpp includes set.h.
Remember that including a file simply pastes its code. There is no need for set.cpp to know about set.h as they will be one file when compiling.
Also, you shouldn't call set.cpp a cpp file. cpp files are ones that are meant to generate object files. The implementation of a template class must be recompiled for each separate type argument, so it must be in a header and cannot form a separate object. It's okay to separate implementation from declaration, but do it in a file like set_implementation.h to avoid confusion.

Karolis Juodelė
  • 3,708
  • 1
  • 19
  • 32
  • Your logic is convincing, but I tried removing the .h references from the .cpp files and this resulted in many errors, so I put them back in. – forest.peterson Jun 19 '12 at 05:33
  • My guess is that, whether you use a command line compiler or an IDE, you've put set.cpp together with other cpp files. As set.cpp is in fact a header file, you can remove it from your project (makefile, etc., but not delete it) and see what happens. Note that the compiler doesn't need to be told about headers. It will find the files needed using the paths specified with #include directive. – Karolis Juodelė Jun 19 '12 at 10:52
  • 1
    Karolis Juodele should have said "There is no need for set.h to know about set.cpp". forest.peterson's failure is unsurprising. – mabraham May 28 '13 at 16:57