Why does this compile if the class is incomplete type?

102 views Asked by At

In Memory.h I have:

#pragma once

class Memory
{public:
    template <typename T, typename ... TArgs>
    static T* newAlloc(TArgs ... args)
    {
        return new T(args ...);
    }
};

And in main.cpp I have:

#include "Memory.h" // The template class is defined here

class Foo
{public:
    Foo(int a, const char* c) {}
};

int main()
{
    Memory::newAlloc<Foo>(7, "str");

}

And this compiles fine even though Foo isn't fully defined until after I pasted in Memory.h. I'm confused about why this compiles. Isn't it true the equivalent code after the compiler has pasted in Memory.h is like this in main.cpp:

class Memory
{
public:
    static Foo* newAlloc(int a, const char* c)
    {
        return new Foo(a, c);
    }
};

class Foo
{public:
    Foo(int a, const char* c) {}
};

int main()
{
      Memory::newAlloc(7, "str");
}

??? Because this doesn't compile, I get the error:

'newAlloc' identifier not found 'newAlloc' is not a member of Memory

Basically it wants the full definition of Foo. If I place the Foo class definition above the Memory one it then compiles fine. So given that my second version is the equivalent of code after template instantiation (is it?) then why does the first version compile but the second not?

I am on Visual Studio 2019 16.4.5

2

There are 2 answers

0
eerorika On

Isn't it true the equivalent code after the compiler has pasted in Memory.h is like this in main.cpp:

No, it isn't true. This would be equivalent:

class Memory
{public:
    template <typename T, typename ... TArgs>
    static T* newAlloc(TArgs ... args)
    {
        return new T(args ...);
    }
};


class Foo
{public:
    Foo(int a, const char* c) {}
};

int main()
{
    Memory::newAlloc<Foo>(7, "str");

}

You'll find that this compiles.

why does the first version compile

It works because Foo is defined before the template is instantiated with Foo as template argument.

0
cigien On

this compiles fine even though Foo isn't fully defined until after I pasted in Memory.h

Yes, because by the time Memory::newAlloc is instantiated here:

Memory::newAlloc(7, "str");

the definition of Foo already exists, and so this compiles fine.


Isn't it true the equivalent code after the compiler has pasted in Memory.h is like this in main.cpp:

No, in this case, on this line:

static Foo* newAlloc(int a, const char* c)

since Foo has not yet been defined, the code will not compile.