2017-09-21 2 views
1

eine Situation vorstellen, wo ich zwei verschiedene Übersetzungseinheiten a.cppWidersprüchliche Template-Definitionen und ODR

#include <iostream> 

double bar(); 

template <typename T> 
T foobar(T t) { 
    return t; 
} 

int main() { 
    std::cout << "foobar called from b.cpp: " << bar() << '\n'; 
    std::cout << "foobar called from a.cpp: " << foobar(1.) << '\n'; 
} 

und b.cpp haben:

template <typename T> 
T foobar(T t) { 
    return t + 1.; 
} 

double bar() { 
    return foobar(1.); 
} 

Ich weiß, dass für Vorlagen, gibt es Ausnahmen von das ODR, dh der Compiler wird instanziierte Funktionsvorlagen als solche markieren und alle außer einem während des Verknüpfungsvorgangs streichen. Mir ist aufgefallen, dass es dem Compiler eigentlich egal ist, ob die generierten Codes solcher Instanziierungen bei verschiedenen Übersetzungseinheiten tatsächlich identisch oder zumindest äquivalent sind.

Im obigen Code ist dies der Fall. Beim Kompilieren, Verknüpfen und läuft mit

c++ a.cpp b.cpp -o result -std=c++17 && ./result 

es das Ergebnis liefern wird

foobar called from b.cpp: 1 
foobar called from a.cpp: 1 

So offenbar, bekam weg für diese eine von u.a. zugunsten der Instanziierung innerhalb der Objektdatei b.o geworfen Beim Übersetzen und Binden mit b.cpp und a.cpp getauscht, wie

c++ b.cpp a.cpp -o result -std=c++17 && ./result 

das Ergebnis wird

foobar called from b.cpp: 2 
foobar called from a.cpp: 2 

sein, so das genaue Gegenteil geschieht: die Instanziierung, die zuerst in der Liste erwähnt wurde von zu Verbundene Objektdateien sind diejenigen, die überlebt haben. Wird ein solches Verhalten irgendwo im Standard definiert? Je nach Build-System kann die Reihenfolge, in der die Objektdateien erwähnt werden, ziemlich willkürlich sein, aber wie in solchen Beispielen führt dies zu sehr unterschiedlichen Programmen und möglicherweise umständlichen Fehlern. Auch wenn ich die Version von a.cpp von bis explizit zu instanziiert versuchen Sie

template double foobar<double>(double); 

es wird nicht das Foobar machen <> Vorlage aus a.cpp überleben, wenn sie vor a.o in der Linkerliste zu erwähnen b.o.

+0

nur aus Neugier: Ist das eine rein akademische Frage, oder haben Sie einen echten Fall, in dem das ein Problem ist? Ich meine, du könntest die Vorlage nur einmal definieren und das Problem ist weg. – user463035818

+2

Es sieht so aus, als ob du das Tag [tag: sprachanwalt] zu deiner Frage hinzufügen möchtest !? –

+0

@WernerHenze, die meine Frage beantwortet;) – user463035818

Antwort

3

Ich weiß, dass für Vorlagen, gibt es Ausnahmen von der ODR

Es gibt keine Ausnahmen für ODR für eine Vorlage, es ist nur, dass Template-Funktion inline werden.

Und Ihr Programm hat ODR-Verletzung.
Sie hätten ein ähnliches Problem mit regulären Inline-Funktionen.

+0

Ich kann das reproduzieren.Ich war mir nicht bewusst, dass Sie offensichtlich ODR verletzen können und so leicht in UB laufen können, ohne dass der Linker einen Fehler oder eine Warnung erzeugt, im Grunde nur durch Hinzufügen einer Inline- oder Template-Funktionsdefinition. – Jodocus