1. ホーム
  2. c++

[解決済み] エラー C2995: 関数テンプレートは既に定義されています。

2022-01-30 01:43:26

質問内容

このコードは 17 エラー C2995: 関数テンプレートは既に定義されています。#include "set.h" ヘッダーを追加する前に別のエラーのセットがありました。これに関連するプライベート.cppと.hファイルがあります。

/*
 * 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

ヘッダーファイル

/*
 * 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

どこが悪いのか

どうすればいい?

set.hはset.cppを、set.cppはset.hを含むという循環依存性が問題です。
あるファイルをインクルードすると、そのファイルのコードが単純に貼り付けられることを思い出してください。コンパイル時に1つのファイルになるので、set.cppがset.hについて知っている必要はありません。
また、set.cppをcppファイルと呼んではいけません。cppファイルとは、オブジェクトファイルを生成するためのものです。テンプレートクラスの実装は、型の引数を分けるごとに再コンパイルする必要があるため、ヘッダに記述する必要があり、別のオブジェクトを形成することはできません。実装と宣言を分けるのは良いのですが、混乱を避けるためにset_implementation.hのようなファイルで行ってください。