Forward declaration being ignored?

柔情痞子 提交于 2019-12-23 06:12:35

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!