Por que um tipo incompleto é detectado no clang dentro de um método de modelo?

Hoje, encontrei um problema de compilação no clang que me surpreendeu. Eu acho que é razoável, mas eu gosto de ir mais fundo e ouvir mais detalhes. Algumas referências padrão, se possível também.

Eu tenho uma classe com um método de modelo que depende de um membro cujo tipo é indefinido no cabeçalho (mas não na fonte). Algo como o seguinte:

// Menu.h
class Page;

class Menu
{
public:
    .... // stuff

template<class Visitor>
void VisitWidget( Visitor&& visitor);

private:
std::unique_ptr<Page> m_page; // destructor implemented in source file, so Page is an incomplete type
};

template<class Visitor>
inline void Menu::VisitWidget( Visitor&& visitor);
{
    m_page->Visit( std::forward<Visitor>(visitor) );
}

No VisualStudio, ele compila. Eu espero que isso só reclame ao instanciar; tão inlining. No entanto, no clang, isso não é compilado assim que alguém inclui o cabeçalho. Forçando-me a incluir Page.h no Menu.h (que eu quero evitar a todo custo).

Gostar:

// Another.cpp (not Menu.cpp)
#include "Menu.h" // this trigger and error due Page is an incomplete type

mesmo que o Another.cpp inteiro não esteja usando o VisitWidget (mesmo em outros cabeçalhos)

Eu acho que isso é causado pelo inline de alguma forma, já que o compilador não é obrigado a realmente usá-lo, mas como existem modelos no meio, não tenho tanta certeza. O clang está realmente checando o tipo?

questionAnswers(1)

yourAnswerToTheQuestion