Ошибка компилятора c2995

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

description title ms.date f1_keywords helpviewer_keywords ms.assetid

Learn more about: Compiler Error C2995

Compiler Error C2995

11/04/2016

C2995

C2995

a57cdfe0-b40b-4a67-a95c-1a49ace4842b

Compiler Error C2995

‘function’ : function template has already been defined

Make sure that there is only one definition for each member function of a templated class.

The following sample generates C2995:

// C2995.cpp
// compile with: /c
template <class T>
void Test(T x){}

template <class T> void Test(T x){}   // C2995
template <class T> void Test2(T x){}   // OK
description title ms.date f1_keywords helpviewer_keywords ms.assetid

Learn more about: Compiler errors C2900 Through C2999

Compiler errors C2900 Through C2999

06/01/2022

C2900

C2901

C2905

C2907

C2915

C2916

C2922

C2924

C2925

C2926

C2938

C2949

C2950

C2954

C2956

C2960

C2961

C2963

C2964

C2965

C2966

C2967

C2968

C2972

C2980

C2981

C2982

C2983

C2984

C2985

C2986

C2987

C2997

C2999

C2900

C2901

C2905

C2907

C2915

C2916

C2922

C2924

C2925

C2926

C2938

C2949

C2950

C2954

C2956

C2960

C2961

C2963

C2964

C2965

C2966

C2967

C2968

C2972

C2980

C2981

C2982

C2983

C2984

C2985

C2986

C2987

C2997

C2999

e3440738-e11b-4878-9ae3-6bc6c53ba461

Compiler errors C2900 Through C2999

The articles in this section of the documentation explain a subset of the error messages that are generated by the compiler.

[!INCLUDEerror-boilerplate]

Error messages

Error Message
Compiler error C2900 declarator‘: member function templates in WinRT classes must be ‘private’, ‘internal’ or ‘protected private’
Compiler error C2901 identifier‘: A generic interface or delegate cannot be public
Compiler error C2902 token‘: unexpected token following ‘template/generic’, identifier expected (Obsolete in Visual Studio 2022.)
Compiler error C2903 identifier‘: symbol is neither a class template/generic nor a function template/generic
Compiler error C2904 identifier‘: name already used for a template in the current scope
Compiler error C2905 Obsolete.
Compiler error C2906 template‘: explicit specialization requires ‘template <>’
Compiler error C2907 register argument ‘number‘ does not specify a valid register number
Compiler error C2908 explicit specialization; ‘template‘ has already been instantiated
Compiler error C2909 identifier‘: explicit instantiation of function template requires return type
Compiler error C2910 function‘: cannot be explicitly specialized
Compiler error C2911 member‘: cannot be declared or defined in the current scope
Compiler error C2912 explicit specialization ‘declaration‘ is not a specialization of a function template
Compiler error C2913 explicit specialization; ‘declaration‘ is not a specialization of a class template
Compiler error C2914 identifier‘: cannot deduce template/generic argument as function argument is ambiguous
Compiler error C2915 identifier‘: ‘type‘ cannot be directly used on the published surface of a WinRT type. Use ‘Platform::Object^’ instead to pass this type
Compiler error C2916 identifier‘: [FlagsAttribute] must (only) be specified on a public enum with an ‘unsigned int’ underlying type
Compiler error C2917 identifier‘: invalid template-parameter (Obsolete in Visual Studio 2022.)
Compiler error C2918 identifier‘: Indexed properties cannot be used on the published surface of a WinRT type
Compiler error C2919 type‘: Operators cannot be used on the published surface of a WinRT type
Compiler error C2920 redefinition: ‘type‘: class template/generic has already been declared as ‘declaration
Compiler error C2921 redefinition: ‘type‘: class template/generic is being redeclared as ‘declaration
Compiler error C2922 interface‘: A WinRT interface cannot contain static members
Compiler error C2923 type‘: ‘identifier‘ is not a valid template/generic type argument for parameter ‘parameter
Compiler error C2924 __declspec(interrupt) routine argument not in R2
Compiler error C2925 __declspec(interrupt) routine cannot use floating-point
Compiler error C2926 identifier‘: a default member initializer is not allowed for a member of an anonymous struct within a union
Compiler error C2927 identifier‘: a function template must be called with at least one argument
Compiler error C2928 explicit instantiation; ‘identifier‘ is not a function or static data member of template-class ‘class
Compiler error C2929 declarator‘: explicit instantiation; cannot explicitly force and suppress instantiation of template-class member
Compiler error C2930 class‘: template-id/generic-id redefined as an enumerator of ‘enum identifier
Compiler error C2931 class1‘: template-id/generic-id redefined as a member function of ‘class2‘ (Obsolete in Visual Studio 2022.)
Compiler error C2932 type‘: template-id/generic-id redefined as a data member of ‘identifier‘ (Obsolete in Visual Studio 2022.)
Compiler error C2933 type‘: template-id/generic-id redefined as a typedef member of ‘identifier‘ (Obsolete in Visual Studio 2022.)
Compiler error C2934 type‘: template-id/generic-id redefined as a nested ‘item‘ of ‘identifier‘ (Obsolete in Visual Studio 2022.)
Compiler error C2935 type‘: template-id/generic-id redefined as a global function (Obsolete in Visual Studio 2022.)
Compiler error C2936 type‘: template-id/generic-id redefined as a global data variable (Obsolete in Visual Studio 2022.)
Compiler error C2937 type‘: template-id/generic-id redefined as a global typedef (Obsolete in Visual Studio 2022.)
Compiler error C2938 identifier‘ : Failed to specialize alias template
Compiler error C2939 type‘: template-id/generic-id redefined as a local data variable (Obsolete in Visual Studio 2022.)
Compiler error C2940 type‘: template-id/generic-id redefined as a local typedef (Obsolete in Visual Studio 2022.)
Compiler error C2941 type‘: template-id/generic-id redefined as a local ‘item‘ (Obsolete in Visual Studio 2022.)
Compiler error C2942 type‘: template-id/generic-id redefined as a formal argument of a function (Obsolete in Visual Studio 2022.)
Compiler error C2943 type‘: template-id/generic-id redefined as a type argument of a template (Obsolete in Visual Studio 2022.)
Compiler error C2944 type‘: template-id/generic-id redefined as a value argument of a template (Obsolete in Visual Studio 2022.)
Compiler error C2945 explicit instantiation does not refer to a template-class specialization
Compiler error C2946 explicit instantiation; ‘type‘ is not a template-class specialization
Compiler error C2947 expecting ‘>’ to terminate template arguments, found ‘token
Compiler error C2948 explicit instantiation; storage class specifier ‘specifier‘ not permitted on specialization
Compiler error C2949 thread_local is not supported with /kernel
Compiler error C2950 Obsolete.
Compiler error C2951 template/generic declarations are only permitted at global, namespace, or class scope
Compiler error C2952 declaration‘: template/generic declaration missing template/generic parameter list
Compiler error C2953 type‘: class template has already been defined
Compiler error C2954 instruction word argument not in range
Compiler error C2955 type‘: use of class template/generic requires template/generic argument list
Compiler error C2956 usual deallocation function ‘function‘ would be chosen as placement deallocation function
Compiler error C2957 token‘: invalid left delimiter: expected ‘<‘
Compiler error C2958 the left delimiter found at ‘file(line_number)’ was not matched correctly
Compiler error C2959 a generic class or function may not be a member of a template
Compiler error C2960 Obsolete.
Compiler error C2961 function‘: inconsistent explicit instantiations, a previous explicit instantiation did not specify ‘argument
Compiler error C2962 syntax error: ‘token‘: expected template-class member function definition to end with ‘}’
Compiler error C2963 Obsolete.
Compiler error C2964 Obsolete.
Compiler error C2965 __declspec(specifier) is not supported with /kernel
Compiler error C2966 identifier1‘: must have the same __declspec(code_seg(…)) as its base class ‘identifier2‘ (Obsolete in Visual Studio 2022.)
Compiler error C2967 identifier‘: an overriding virtual function must have the same __declspec(code_seg(…)) as an overridden virtual function (Obsolete in Visual Studio 2022.)
Compiler error C2968 identifier‘: recursive alias declaration
Compiler error C2969 syntax error: ‘token‘: expected member function definition to end with ‘}’
Compiler error C2970 type‘: template parameter ‘parameter‘: ‘argument‘: an expression involving objects with internal linkage cannot be used as a non-type argument
Compiler error C2971 type‘: template parameter ‘parameter‘: ‘argument‘: a variable with non-static storage duration cannot be used as a non-type argument
Compiler error C2972 type‘: template parameter ‘parameter‘: the type of non-type argument is invalid
Compiler error C2973 template‘: invalid template argument ‘number
Compiler error C2974 type‘: invalid template/generic argument for ‘parameter‘, type expected
Compiler error C2975 type‘: invalid template argument for ‘parameter‘, expected compile-time constant expression
Compiler error C2976 type‘: too few template/generic arguments
Compiler error C2977 type‘: too many template/generic arguments
Compiler error C2978 syntax error: expected ‘keyword1‘ or ‘keyword2‘; found type ‘type‘; non-type parameters are not supported in generics
Compiler error C2979 explicit specializations are not supported in generics
Compiler error C2980 C++ exception handling is not supported with /kernel
Compiler error C2981 the dynamic form of ‘keyword‘ is not supported with /kernel
Compiler error C2982 declaration‘: different __declspec(code_seg(…)) used: was ‘identifier1‘ now ‘identifier2
Compiler error C2983 declaration‘: all declarations must have an identical __declspec(code_seg(…))
Compiler error C2984 Obsolete.
Compiler error C2985 argument‘: the argument to __declspec(code_seg(…)) must be a text section
Compiler error C2986 identifier‘: __declspec(code_seg(…)) can only be applied to a class or a function
Compiler error C2987 a declaration cannot have both __declspec(code_seg(‘identifier‘)) and __declspec(code_seg(‘value‘))
Compiler error C2988 unrecognizable template declaration/definition
Compiler error C2989 class‘: class template/generic has already been declared as a non-class template/generic
Compiler error C2990 class‘: non-class template/generic has already been declared as a class template/generic
Compiler error C2991 redefinition of template/generic parameter ‘parameter
Compiler error C2992 class‘: invalid or missing template/generic parameter list
Compiler error C2993 type‘: illegal type for non-type template parameter ‘identifier
Compiler error C2994 unnamed class in template parameter list
Compiler error C2995 declaration‘: function template has already been defined
Compiler error C2996 function‘: recursive function template definition
Compiler error C2997 function‘: array bound cannot be deduced from a default member initializer
Compiler error C2998 declarator‘: cannot be a template definition
Compiler error C2999 UNKNOWN ERROR Please choose the Technical Support command on the Visual C++ Help menu, or open the Technical Support help file for more information

See also

C/C++ Compiler and build tools errors and warnings
Compiler errors C2000 — C3999, C7000 — C7999

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

Я использую 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

  • Forum
  • General C++ Programming
  • error C2995 while compiling

error C2995 while compiling

Hi,
1) When i`m trying to compile this, i`m getting this error:
node.h(48): error C2995: ‘std::ostream &operator <<(std::ostream &,const Node<T> &)’ : function template has already been defined
Any reason why ?

2) on Tree.h , there is a problem with _root = new Node<element>;
can you tell me why ?!

Movie.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <string>
#include <ostream>
#include "Movie.h"	

using namespace std;

	int Movie::getScore() const {
		return _score;
	}

	string Movie::getName() const {
		return _name;
	}

	bool Movie::operator < (const Movie& movie2) const {
		if (this ==  &movie2) {
			return false;
		}
		if (getScore() < movie2.getScore() )
			return true;
		if (getScore() > movie2.getScore() )
			return false;

		if ((getName().compare(movie2.getName())) < 0 )
			return true;
		return false;
	}

	bool Movie::operator==(const Movie& movie2) const {
		if (*this ==  movie2) {
			return true;
		}
		if (!(getScore() == movie2.getScore() ) && !(getName() == movie2.getName()) ) // str1.compare(str2)
			return true;
		return false;
	}

	ostream& operator<<(ostream& out, const Movie& movie) {
		out << movie._name << "(" << movie._score << ")." << endl;
		return out;
	}

Movie.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef _MOVIE_H_
#define _MOVIE_H_

#include <string>
#include <ostream>

using namespace std;

class Movie {
public:
	Movie(string name, int score);

	int getScore() const;
	string getName() const;
	
	/* movie1 is smaller than  movie2,
	*  if its score is smaller. 
	*  If the scores are the same, their names should be lexicographic compared*/
	bool operator<(const Movie& ) const;
	
	/* movie1 equals movie2 if their scores and names are the same */
	bool operator==(const Movie&) const;

	/* Should output the movie name and movie score */
	friend ostream& operator<<(ostream& out, const Movie& node);
private:
	int _score;
	string _name;
};

#endif 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#ifndef _NODE_H_
#define _NODE_H_

#include <iostream>
#include <list>

using namespace std;

template <class T> 
class Node{
public:
	Node(){
		_parent = _left = _right = 0;
		_element = 0;
	}

	Node(T element){
		_parent = _left = _right = 0;
		_element = element;
	}

	Node& operator=(const Node& node){
		if (this == &node)
			return *this;
		delete[] _element;
		_element = new T;
		_element = node._element;
		return *this;
	}


	bool operator<(const Node& node) const {
		if (this == &node)
			return false;
		if (_element < node._element)
			return true;
		return false;
	}
	
	bool operator==(const Node& node) const {
		if (this == &node)
			return true;
		if (_element == node._element )
			return true;
		return false;
	}
	/*This function should call the operator<< of the node's element*/
	template <class T2> friend ostream& operator<<(ostream& out, const Node<T2>& node){
		out << node._element << endl;
		return out;
	}

//       parent set/get           //
	Node* getParent() const {
		return _parent;
	}

	void setParent(Node* node){
		_parent = node;
	}

//       right set/get           //
	Node* getRight() const{
		return _right;
	}

	void setRight(Node* node){
		_right - node;
	}

//       left set/get           //
	Node* getLeft() const{ 
		return _left;
	}

	void setLeft(Node* node) {
		_left = node;
	}

//       element set/get           //
	T getElement() const{
		return _element;
	}

	void setElement(T ele){
		_element = ele;
	}

private:
	Node* _parent;
	Node* _right;
	Node* _left;
	T _element;
};

#endif 

Tree.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#ifndef _TREE_H_
#define _TREE_H_

#include <iostream>
#include "Node.h"

using namespace std;

template <class T>
class Tree{
public:
	Tree():_root(NULL){};

	/*Should return the root of the tree
	* if the tree is empty should return NULL
	*/
	Node<T>* getRoot() const{
		if (_root == NULL)
			return NULL;
		return _root;
	}

	/* Should return the node that contains the input paramter.
	* if such node does not exist, should return NULL
	*/	
	Node<T>* findNode(const T& element) const{
		Node<T>* tmp = _root;
		while (tmp != NULL) {
			if (tmp->getElement() == element) {
				return tmp;
			} else {
				if (tmp->getElement() < element) {
					tmp = tmp->getLeft();
				} else {
					tmp = tmp->getRight();
				}
			}
		}
		return NULL;
	}

	/*Should return the node with the maximal value
	* if the tree is empty should return NULL
	*/
	Node<T>* getMaximum() const{
		Node<T>* tmp = _root;
		while (tmp->getRight())
			tmp = tmp->getRight();
		return tmp;
	}

	/* Should delete the node with input parameter from the tree, 
	 * if a node with this value does not exist, returns false 
	 * if the deletion succeeded returns true
	 * otherwise, returns false 
	 */
	bool deleteElement(const T& element){
		Node<T>* tmp;//= findNode(T&);
		tmp = findNode(element);
		return deleteAndFix(tmp);
	}

	/* Should delete the node todelete from the tree, 
	 * if the deletion succeeded returns true
	 * otherwise, returns false 
	 */
	bool deleteNode(Node<T>* todelete){
		Node<T>* tmp = findNode(todelete->_element);
		return deleteAndFix(tmp);
	}

	/*Should add a node with input value to the tree
	* if a node with the same value exists, the function should return false
	* otehrwise, it should return true
	*/
	bool addElement(const T& element){
		if (_root == NULL){
			_root = new Node<element> ; //Here 
			_root->setElement(element);
			return true;
		}
		if (findNode(element))
			return false;
		Node<T>* tmp = _root, next = NULL;
		bool isLeft = true;
		do {
			if (tmp->getElelemt() < element){
				next = tmp->getLeft();
				isLeft = true;
			}
			else {
				next = tmp->getRight();
				isLeft = false;
			}
		} while (next != NULL);
		next = new Node<element>;
		next->setElement(element);
		next->setParent(tmp);
		if (isLeft)
			tmp->setLeft(next);
		else
			tmp->setRight(next);
	}


	/*Should print the tree in ascending order. 
	* (first value is the smallest node in the tree)
	* if the tree is empty, it should print 'The tree is empty'
	*/
	void printTree() const{
		if (_root == NULL){
			cout << "The Tree is Empty." << endl;
			return;
		}
	}


private:
	Node<T>* _root;
//	void inorder(Node<T>*) const;
	bool deleteAndFix(Node<T>* tmp){
		if (tmp == NULL)
			return false;
		if (tmp->getRight() == NULL){
			if (tmp->getLeft() == NULL){
				delete tmp;
				return true;
			} else {
				tmp->getLeft()->setParent(tmp->getParent());
				tmp->getParent()->setLeft(tmp->getLeft());
				delete tmp;
				return true;
			}
		} else {
			Node<T>* tmp2 = tmp;
			tmp = tmp->getRight();
			while (tmp->getLeft() != NULL)
				tmp = tmp ->getLeft();
			if (tmp->getParent() != tmp2)
				tmp->getParent->setLeft(NULL);
			tmp->setRight(tmp2->getRight());
			tmp->setLeft(tmp2->getLeft());
			tmp->setParent(tmp2->getParent());
			if (tmp2->getLeft() != NULL) 
				tmp2->getLeft()->setParent(tmp);
			tmp2->getRight()->setParent(tmp);
			if (tmp2->getParent()->getLeft() == tmp2)
				tmp2->getParent()->setLeft(tmp);
			else
				tmp2->getParent()->setRight(tmp);
			delete tmp2;
			return true;
		}
		return false;
	}
};

#endif	 

Last edited on

1. First is because when you have different types for T, operator<T2> << is defined for each of them. Since T2 is not the same as T, cout << Node<float> could call a << defined in Node<float> as well as the one in Node<int>, or etc. I think.. To solve this, try removing T2 and replacing it with T.

2. in _root = new Node<element>, element is not a type. This should probably be new Node<T>(element) instead.

Topic archived. No new replies allowed.

этот код генерирует 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

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

Проблема в том, что operator*() определяется внутри в шаблоне класса matrix.

Итак, когда вы определяете объект matrix, скажем, matrix<double, 1, 2>, эта функция определяется; когда вы определяете другой объект с тем же типом и разными размерами, скажем, matrix<double, 2, 1>, точно такая же функция шаблона переопределяется.

Мне кажется, что нет ничего, что требовало бы, чтобы эта функция была friend из matrix, поэтому — предложение — удалите ее внутри класса и перепишите снаружи, как показано ниже.

template <class Type, std::size_t N>
using container = std::array<Type, N>;

using size_type                     = std::size_t;

template <typename value_type, std::size_t Rows_lhs, std::size_t Columns_lhs,
          std::size_t Rows_rhs, std::size_t Columns_rhs>
constexpr matrix<value_type, Rows_lhs, Columns_rhs> operator*(
    const matrix<value_type, Rows_lhs, Columns_lhs>& lhs,
    const matrix<value_type, Rows_rhs, Columns_rhs>& rhs)
{
    static_assert(Columns_lhs == Rows_rhs, "Incorrect matrix for product!");

    matrix<value_type, Rows_lhs, Columns_rhs> result{};
    container<value_type, Rows_rhs> thatColumn{};

    for (size_type j = 0; j < Columns_rhs; ++j)
    {
        for (size_type k = 0; k < Rows_rhs; ++k)
        {
            thatColumn.at(k) = rhs(k, j);
        }

        for (size_type i = 0; i < Rows_lhs; ++i)
        {
            const auto thisRow = lhs(i);
            value_type summand{};
            for (size_type k = 0; k < Rows_rhs; ++k)
            {
                summand += thisRow.at(k) * thatColumn.at(k);
            }
            result(i, j) = summand;
        }
    }
    return result;
}

Если вы действительно хотите, вы можете сохранить его friend, но только объявив его внутри класса matrix

template <typename value_type, std::size_t Rows_lhs, 
          std::size_t Columns_lhs, std::size_t Rows_rhs, 
          std::size_t Columns_rhs>
friend constexpr matrix<value_type, Rows_lhs, Columns_rhs> operator*(
    const matrix<value_type, Rows_lhs, Columns_lhs>& lhs,
    const matrix<value_type, Rows_rhs, Columns_rhs>& rhs); 

Дополнительное (не по теме) предложение: нет необходимости определять размерность матрицы четыре и налагать с помощью static_assert(), что второй (Columns_lhs) и третий (Rows_rsh) равны.

Вы можете объединить их в одном параметре шаблона (midDim, в следующем примере)

template <typename value_type, std::size_t Rows_lhs, std::size_t midDim,
          std::size_t Columns_rhs>
constexpr matrix<value_type, Rows_lhs, Columns_rhs> operator*(
    const matrix<value_type, Rows_lhs, midDim>& lhs,
    const matrix<value_type, midDim, Columns_rhs>& rhs)
{
    matrix<value_type, Rows_lhs, Columns_rhs> result{};
    container<value_type, midDim> thatColumn{};

    for (size_type j = 0; j < Columns_rhs; ++j)
    {
        for (size_type k = 0; k < midDim; ++k)
        {
            thatColumn.at(k) = rhs(k, j);
        }

        for (size_type i = 0; i < Rows_lhs; ++i)
        {
            const auto thisRow = lhs(i);
            value_type summand{};
            for (size_type k = 0; k < midDim; ++k)
            {
                summand += thisRow.at(k) * thatColumn.at(k);
            }
            result(i, j) = summand;
        }
    }
    return result;
}

Понравилась статья? Поделить с друзьями:
  • Ошибка компилятора c2784
  • Ошибка компиляции для платы arduino nano что делать
  • Ошибка компилятора c2731
  • Ошибка компиляции для платы arduino nano как исправить
  • Ошибка компилятора c2679