2016-06-02 19 views
3

Heute stieß ich auf ein Kompilierproblem beim Klang, das mich überraschte. Ich denke, es ist vernünftig, aber ich mag es, tiefer zu graben und mehr Details zu hören. Einige Standardreferenzen wenn möglich auch.Warum wird ein unvollständiger Typ innerhalb einer Template-Methode erkannt?

Ich habe eine Klasse mit einer Template-Methode, die auf einem Mitglied, dessen Typ ist nicht definiert in der Kopfzeile (aber nicht in der Quelle). So etwas wie das Folgende:

// 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)); 
} 

In VisualStudio kompiliert es. Ich erwarte, dass sich dies nur beim Instanciating beschweren wird; so inlining. In clang wird dies jedoch nicht kompiliert, sobald jemand den Header hinzufügt. Erzwingt, dass ich Page.h in Menu.h einfüge (was ich um jeden Preis vermeiden möchte).

Like:

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

, auch wenn die ganze Another.cpp nicht VisitWidget (auch in anderen Header) mit

Ich denke, dass dies irgendwie durch Inline verursacht wird, da der Compiler nicht verpflichtet ist, um es wirklich zu benutzen, aber da es Templates in der Mitte gibt bin ich mir nicht so sicher. Klingt wirklich der Typ?

+0

@chris, siehe meine Antwort. Es ist ein bekannter Fehler in MSVC. – SergeyA

Antwort

8

Ja, das kompiliert in MSVC, weil es einen bekannten Bug hat. Es implementiert keine zweistufige Vorlageninstanziierung.

Um zu erarbeiten. MSVC verschiebt das Vorlagenparsen fälschlicherweise, bis es tatsächlich in dem Code instanziiert wird. Wahrscheinlich passiert es, nachdem die volle Page Definition sichtbar wird.

Der Standard fordert jedoch, dass die Vorlage zum Zeitpunkt der Definition vorparsiert wird, und alle Typen, die nicht von Vorlagenargumenten abhängig sind, werden aufgelöst. Dies schlägt fehl, da m_page nicht von einem Besucherargument abhängig ist - und zu diesem Zeitpunkt noch unvollständig ist.

P.S. Ich kann nicht einmal ausdrücken, wie empört ich über MSFT für diese eklatante Standardverletzung (unter anderem) bin. Es macht die plattformübergreifende Entwicklung zu einem echten Problem, wenn MS-konformer Code an konforme Compiler portiert werden muss.

+0

Ich würde es lieber "deficiency" anstatt "bug" nennen, weil afaik MSVC niemals behauptete, Zweiphasen-Lookup zu implementieren. – Pixelchemist

+1

@Pixelchemist, wir können Wörter so viel jonglieren wie wir wollen. Aber ich nenne eine eklatante Verletzung der eindeutig vorgeschriebenen Standardregel einen Fehler. Ich kann sogar hinzufügen (auf den Schmerz, beschämt zu werden), dass ich selbst kein großer Fan der zweistufigen Instanziierung bin. Ich verstehe die Gründe und alles, aber es macht oft das Leben des Programmierers schwieriger. Aber wenn es in Standard ist, müssen Sie es implementieren! – SergeyA

+1

Pixelchemist - sie müssen nicht "behaupten", sie implementieren es. Nur zu sagen, dass sie C++ anbieten, impliziert, dass sie es richtig machen. Klar, es ist ein Fehler. – mrunion