问题
I have the below class (which is basically a wrapper for std::vector), and one of the functions returns a variable of the type AInteger (which is basically a wrapper for int). Now the type AInteger is used multiple times throughout the class, yet the compiler starts complaining at a very specific position. When I remove the "getSize()" function, everything compiles just fine.
There is mutual inclusion, so I need the forward declaration for everything to work.
One of the problems is that the AList class is a template, so it is impossible to move the definitions to a .cpp file (which would normally solve the problem).
What am I doing wrong?
Here's the class:
#ifndef ALIST_H
#define ALIST_H
#include <vector>
#include "AInteger.h"
class AInteger;
template<typename VALUE>
class AList {
public:
AList() {
}
AList(const std::vector<VALUE> list) {
value = list;
}
~AList() {
}
operator const std::vector<VALUE>() const {
return value;
}
std::vector<VALUE> toStdVector() const {
return value;
}
VALUE operator [](const AInteger index) const {
return value.at(index);
}
void add(const VALUE value) {
this->value.push_back(value);
}
VALUE get(const AInteger index) const {
return value[index];
}
AInteger getSize() const { // ERROR OCCURS HERE
return value.size();
}
void remove(const AInteger index) {
value.erase(index);
}
private:
std::vector<VALUE> value;
};
#endif
Output:
1>------ Build started: Project: ALibrary, Configuration: Debug Win32 ------
1> ASocket.cpp
1>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
1> AInteger.cpp
1>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
1> AHttpRequest.cpp
1>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
1> ABoolean.cpp
1>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
1> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
1> Generating Code...
1> Compiling...
1> AString.cpp
1> Generating Code...
2>------ Build started: Project: BitHoarder, Configuration: Debug Win32 ------
2> SystemHandler.cpp
2>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
2> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
2> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
2> Main.cpp
2>d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(43): error C2027: use of undefined type 'AInteger'
2> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(8): note: see declaration of 'AInteger'
2> d:\programs\programming\visual studio projects\c++\alibrary\alibrary\alist.h(53): note: see reference to class template instantiation 'AList<VALUE>' being compiled
2> Generating Code...
========== Build: 0 succeeded, 2 failed, 0 up-to-date, 0 skipped ==========
If any more code is needed just ask and I will provide.
Thanks!
EDIT: Here's the code that's inside "AInteger.h"
#ifndef AINTEGER_H
#define AINTEGER_H
#include "AList.h"
template<typename VALUE>
class AList;
class AInteger {
public:
AInteger();
AInteger(const int);
~AInteger();
operator const int() const;
int toInt() const;
AInteger operator=(const AInteger &);
AInteger & operator++();
AInteger & operator--();
AList<AInteger>splitByNumber(const AInteger &);
private:
int value;
};
#endif
To make matters even more confusing, the following class, which does THE EXACT SAME THING does not produce the error:
#ifndef ADICTIONARY_H
#define ADICTIONARY_H
#include <map>
#include "AInteger.h"
class AInteger;
template<typename KEY, typename VALUE, typename COMPARE = std::less<KEY>>
class ADictionary {
public:
ADictionary() {
}
ADictionary(const std::map<KEY, VALUE, COMPARE> dictionary) {
value = dictionary;
}
~ADictionary() {
}
operator const std::map<KEY, VALUE, COMPARE>() const {
return value;
}
std::map<KEY, VALUE, COMPARE> toStdMap() const {
return value;
}
VALUE operator [](const KEY key) const {
return value.at(key);
}
void add(const KEY key, const VALUE value) {
this->value.insert(std::make_pair(key, value));
}
VALUE get(const KEY key) const {
return value[key];
}
AInteger getSize() const { // No error here
return value.size();
}
void remove(const KEY key) {
value.erase(value.find(key));
}
private:
std::map<KEY, VALUE, COMPARE> value;
};
#endif
回答1:
The implementation of getSize()
must create an instance of AInteger
. This is only possible if the full definition of AInteger
is known. You cannot create an instance of a type which is only forward-declared.
And that's exactly what the compiler tells you: error C2027: use of undefined type 'AInteger'
. It does not ignore the forward declaration but tells you that it's not enough.
As for the #include "AInteger.h"
, you do not show its contents, but possible problems are:
- Buggy include guard in the header file causes the compiler to skip the definition.
- The header file defines a different type with a similar name.
- The definition of
AInteger
is within a namespace.
回答2:
What's gone wrong is answered very well in Christian Hackl's answer and normally I'd drop it there, but I can't explain how the OP can fix this properly in a comment.
First a revised AInteger.h
#ifndef AINTEGER_H
#define AINTEGER_H
template<typename VALUE>
class AList;
class AInteger {
public:
AInteger();
AInteger(const int);
~AInteger();
//operator const int() const;
int toInt() const;
AInteger operator=(const AInteger &);
AInteger & operator++();
AInteger & operator--();
std::unique_ptr<AList<AInteger>> splitByNumber(const AInteger &);
void splitByNumber(const AInteger &,
AList<AInteger> &);
private:
int value;
};
#endif
The include of AList.h is gone. The forward declaration of AList
remains I've provided two different splitByNumber
methods. Pick one. The first creates and returns a pointer protected by a smart pointer. The second approach, and my personal preference, takes a reference to an AList created by the caller.
The thing is neither know anything about the inner workings of AList
because all they care is about is A) It exists and b) they can get the address of one.
Bear with me while I explore both because I think they are both educational.
Alist.h remains unchanged except for the removal of the forward declaration of AInteger
.
The two splitByNumber
candidates sit in AInteger
's implementation file which can safely include both AInteger.h and AList.h and thus has complete knowledge of both at the same time and can do all the magical things AIntegers
and ALists
can do.
std::unique_ptr<AList<AInteger>> AInteger::splitByNumber(const AInteger & integer)
{
std::unique_ptr<AList<AInteger>> listp(new AList<AInteger>());
// do stuff with listp
return listp;
}
void AInteger::splitByNumber(const AInteger & integer,
AList<AInteger> & list)
{
// do stuff with list
}
Using the pointer version:
std::unique_ptr<AList<AInteger>> alistp = aitest1.splitByNumber(aitest2);
alistp->add(somenumber);
Using the reference version:
AList<AInteger> alist; // first create an empty AList
aitest1.splitByNumber(aitest2, alist); // pass it into the function
alist.add(somenumber); // use the AList
来源:https://stackoverflow.com/questions/32979842/forward-declaration-being-ignored