Ошибка шаблон функции уже определен

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

Есть много вариантов решения этого вопроса, но мой ответ ничем не отвечает.

Я использую VS 2008. Я пытаюсь создать карту с помощью бинарного дерева поиска

#ifndef _map_h
#define _map_h#include<string>
using namespace std;

template <typename ValType>
class Map
{
public:
Map();
~Map();
ValType getvalue(string key);
void add(string key,ValType value);

private:
struct node{
string key;
ValType value;
node *right;
node *left;
};
node *root;

node *treeSearch(string key,node *t);

void treeEnter(string key,ValType value,node *&t);
};
#include"map.cpp"
#endif

map.cpp

#include<string>
#include<iostream>
#include"map.h"using namespace std;

template <typename ValType>
Map<ValType>::Map(){
root=NULL;
}

template <typename ValType>
Map<ValType>::~Map(){
delete root;
}template <typename ValType>
ValType Map<ValType>::getvalue(string key){
node *found=treeSearch(key,root);
if(found==NULL)
cout<<"Couldnot Found the node";
else return found->value;
}

template <typename ValType>
typename Map<ValType>::node *Map<ValType>::treeSearch(string key,node *t){
if(t==NULL) return NULL;

if(t->key==key) return t;

if(t->key>key) treeSearch(key,t->left);

else treeSearch(key,t->right);
}

template <typename ValType>
void Map<ValType>::add(string key,ValType value){
treeEnter(key,value,root);
}

template <typename ValType>
void Map<ValType>::treeEnter(string key,ValType value,node *&t){
if(t==NULL){
t->value=value;
t->key=key;
t->left=NULL;
t->right=NULL;
}

else if(t->key==key) t->value=value;

else if(t->key>key) treeEnter(key,value,t->left);

else treeEnter(key,value,t->right);
}

Ошибка: для всех функций говорится, что они уже определены.

Я слежу за онлайн-курсом в Стэнфорде, и то же самое с инструктором (она пользовалась Mac)

3

Решение

Вы включили map.h в map.cpp а также map.cpp в map.h, Включить охрану в map.h предотвратит многократное включение map.h и предотвратит бесконечное рекурсивное включение. Однако, если вы кормите map.cpp напрямую к компилятору (что вы, очевидно, пытаетесь сделать) map.h один раз и потом map.h будет включать map.cpp сам еще раз. Это то, что вызывает ошибку.

Если вы хотите реализовать свой шаблон как .cpp файл включен в .h файл, вы можете сделать это. Это странно, но его можно заставить работать. В первую очередь, если вы решили #include ваш map.cppтогда даже не пытайтесь скомпилировать map.cpp, Не кормите своих map.cpp прямо к компилятору. Кроме того, удалить #include "map.h" От этого .cpp файл. В этом нет абсолютно никакого смысла.

Ваша программа будет иметь другие файлы реализации, такие как, скажем, myprogram.cpp, который будет использовать вашу карту. Тот myprogram.cpp должны включать map.h, Тот myprogram.cpp это то, что вы будете давать компилятору. Таким образом, он будет работать как задумано. Но пытаюсь скомпилировать map.cpp напрямую приведет только к ошибкам.

Лучшей идеей было бы не помещать что-либо в .cpp файл. Либо положить все в .h файл или, если вы действительно хотите разделить его таким образом, переименуйте ваш .cpp Перейдите к чему-то другому, чтобы всем было ясно, что это не единица перевода.

4

Другие решения

В моем случае я пропустил include guard или #pragma один раз в верхней части заголовка, где я определил функцию шаблона.

1

этот код генерирует 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 size is unchanged.
* Otherwise, the value is added and set 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 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 contents during
* mapping/iteration.
*/

/*
* Method: mapAll
* Usage: set.mapAll(Print);
* -------------------------
* This method iterates through this set 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 contents
* and calls the function fn once for each element, passing
* the element and the client data. That data can be of whatever
* type is needed for the client 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

Где это происходит неправильно

#c #templates #template-specialization

#c #шаблоны #шаблон-специализация

Вопрос:

Я видел много вопросов SO о специализации в контексте методов, но не функций, принадлежащих классам. Мне трудно перевести знания, переданные из этих вопросов, в мою проблему здесь.

Я занимаюсь классом, который я создал в прошлом для изучения, и я хотел бы иметь специализацию для арифметических типов.

 template <typename T>
class Vector3
{
public:
    T x;
    T y;
    T z;

public:
    operator std::string() const;
}
  

Это специализация, которую я пытаюсь сделать:

 template<typename T = std::enable_if<std::is_arithmetic<T>::value, T>::type>
inline Vector3<T>::operator std::string() const {

    std::stringstream ss;
    ss << "NOT NUMBER {" << x << ", " << y << ", " << z << "}";

    return ss.str();
}

template<typename T = std::enable_if<!std::is_arithmetic<T>::value, T>::type>
inline Vector3<T>::operator std::string() const {

    std::stringstream ss;
    ss << "NUMBER {" << x << ", " << y << ", " << z << "}";

    return ss.str();
}
  

Однако, когда я пытаюсь скомпилировать, я получаю

ошибка C2995: ‘Vector3::operator std::string(void) const’: шаблон функции уже определен

Когда я гуглю это, обычно это случаи, когда люди определили свой класс / метод в файле CPP, а также в файле заголовка. Поскольку я делаю это только в заголовочном файле, я могу только предположить, что enable_if неверен. Когда я смотрю на другие примеры, они просто специализируются на , , но я бы хотел использовать is_arithmitic способ.

Что я делаю не так? Заранее спасибо

Ответ №1:

Значение по умолчанию здесь:

 template<typename T = XXX>
inline Vector3<T>::operator std::string() const { ... }
  

вообще не имеет значения, на данный момент вычет не выполняется и T уже определен. Это законно, но это просто шум.

Теперь вы также не можете частично специализировать функцию-член в шаблоне класса, но мы можем использовать черты:

 template <class T>
class Vector3 {
public:
    // ...
    operator std::string() const {
        return as_string(std::is_arithmetic<T>{});
    }

private:
    std::string as_string(std::true_type ) {
        // implementation for arithmetic types
    }

    std::string as_string(std::false_type ) {
        // implementation for non-arithmetic types
    }
};
  

Комментарии:

1. Спасибо за ответ. У меня было ощущение, что после всех поисков в Google мне придется использовать отправку тегов… Я посмотрю, есть ли у кого-нибудь другие идеи, прежде чем отмечать это как правильное.

Ответ №2:

Ответ Барри идеален.

Вот некоторые пояснения и предложения:

http://en.cppreference.com/w/cpp/types/enable_if

«Распространенной ошибкой является объявление двух шаблонов функций, которые отличаются только своими аргументами шаблона по умолчанию. Это незаконно, поскольку аргументы шаблона по умолчанию не являются частью подписи шаблона функции, и объявление двух разных шаблонов функций с одинаковой подписью является незаконным «.

У меня есть этот заголовочный файл:

Utility.h:

#pragma once

#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <Windows.h>

using namespace std;

template<std::size_t> struct int_ {};

template <class Tuple, size_t Pos> 
std::ostream& print_tuple(std::ostream& out, const Tuple& t, int_<Pos>);

struct Timer {
public:
    Timer();
    void start();
    double getMilliSec();
private:
    LARGE_INTEGER frequency;        // ticks per second
    LARGE_INTEGER t1, t2;           // ticks
};

//...

#include "Utility.cpp"

И этот файл реализации:

Utility.cpp:

#include "Utility.h"
template <class Tuple, size_t Pos>
std::ostream& print_tuple(std::ostream& out, const Tuple& t, int_<Pos>) {
     ...
}

Timer::Timer() {
    // get ticks per second
    QueryPerformanceFrequency(&frequency);
}

void Timer::start() {
    QueryPerformanceCounter(&t1);
}

double Timer::getMilliSec() {
    QueryPerformanceCounter(&t2);
    return (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
}

Который возвращает эту ошибку:

error C2995: 'std::ostream &print_tuple(std::ostream &,const Tuple &,int_<Pos>)': function template has already been defined
error C2084: function 'Timer::Timer(void)' already has a body
...

Проблема не в охранниках (как предложено в этом вопросе), так как я использую #pragma once

Я читал о реализации файлов .tpp для реализации класса шаблона, но я считаю это ужасным решением, поскольку Visual Studio ничего не форматирует из этого файла.

попытка определить Utility.tpp: (НЕПРАВИЛЬНОЕ РЕШЕНИЕ)

Поэтому я заменил #include "Utility.cpp на #include "Utility.tpp в Utility.h и определил…

Utility.tpp

Timer::Timer() {
    // get ticks per second
    QueryPerformanceFrequency(&frequency);
}

void Timer::start() {
    QueryPerformanceCounter(&t1);
}

double Timer::getMilliSec() {
    QueryPerformanceCounter(&t2);
    return (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
}

И теперь возвращается ошибка:

1>Memoization.obj : error LNK2005: "public: __cdecl Timer::Timer(void)" (??0Timer@@[email protected]) already defined in HelloWorld.obj
...

Это основное кстати:

HelloWorld.cpp:

#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//#include "Memoization.cpp"
#include<vector>
#include"Utility.h"

using namespace std;

int main()
{
}

пытается определить Utility.tpp: (НАКОНЕЦ-ТО ПРАВИЛЬНОЕ РЕШЕНИЕ)

Как я заметил в комментарии, как идиот, я импортировал методы Time в файл .tpp, и, очевидно, я должен был импортировать функцию шаблонов, поэтому в Utility.tpp содержится print_tuple, а Utility.cpp содержит 3 функции Timer.

Понравилась статья? Поделить с друзьями:
  • Ошибка чтобы установить приложение перейдите в мои приложения
  • Ошибка чтобы создать сетевой мост
  • Ошибка чтобы использовать эту функцию вы должны быть друзьями
  • Ошибка чтобы использовать диск сначала отформатируйте его
  • Ошибка что это толковый словарь