c++templatesc++17c++20legacy-code

The C++ code that using templates doesn't compile in c++ 20, but was ok in c++ 17


I have some legacy code that I want to upgrade to c++20. The code compiles in c++17 without any issues but fails if I switch to C++20. I simplified the code as much as possible, please look at the example. I am using Visual Studio 2022 on Windows



class MyFile
{
public:
    void Read(){ }
};

class ArrayWrapper;

class BaseClass
{
public:
    ArrayWrapper* arrayWrapper;
};

template <class T> class ArrayClass : public BaseClass
{
public:
    void Add()
    {
        arrayWrapper->file.Read();
    }
};


class ArrayWrapper
{
public:
    ArrayWrapper(): file(new MyFile()){ }
    ~ArrayWrapper() { delete file; }
    MyFile* file;
    ArrayClass<int> Array{};
    void Update()
    {
        Array.Add();
    }
};

int main()
{
    ArrayWrapper wrapper;
    wrapper.Update();
}

And this is the error message that I am getting:

error C2027: use of undefined type 'ArrayWrapper'
message : see declaration of 'ArrayWrapper'
message : see reference to class template instantiation 'ArrayClass<T>' being compiled

I did look on the stack overflow and in the C++ docs but couldn't figure out what is wrong with this code in C++ 20 Can someone explain how to fix this issue, please?


Solution

  • Move ArrayClass::Add definition after ArrayWrapper.

    The method and the whole ArrayClass<int> is instantiated right after the definition of the class template, at which point ArrayWrapper is still not fully defined.

    You would get the same error if ArrayClass was not a template.

    class MyFile
    {
    public:
        void Read(){ }
    };
    
    class ArrayWrapper;
    
    class BaseClass
    {
    public:
        ArrayWrapper* arrayWrapper;
    };
    
    template <class T> class ArrayClass : public BaseClass
    {
    public:
        void Add();
    };
    
    
    class ArrayWrapper
    {
    public:
        ArrayWrapper(): file(new MyFile()){ }
        ~ArrayWrapper() { delete file; }
        MyFile* file;
        ArrayClass<int> Array{};
        void Update()
        {
            Array.Add();
        }
    };
    
    template <class T> 
    void ArrayClass<T>::Add()
    {
        arrayWrapper->file->Read();
    }
    
    int main()
    {
        ArrayWrapper wrapper;
        wrapper.Update();
    }
    

    Also, it should be arrayWrapper->file->Read(); file is a pointer.