2017-11-28 3 views
0

ich nicht herausfinden können, warum der Code nicht kompilieren, selbst wenn ich die Wachen sind sich wiederholende KompilationLinker beschwert sich über mehrere Definition sogar Einbeziehung Wachen gibt es

Die Hauptklasse foo.h zu verhindern:

#ifndef FOO_H_INCLUDED 
#define FOO_H_INCLUDED 

#include <iostream> 

class Foo; 

template<int TDim> 
struct Foo_Helper 
{ 
    static bool Compare(const Foo& this_foo, const Foo& other_foo); 
}; 

class Foo 
{ 
public: 
    Foo(const int& Value) : mValue(Value) {} 
    virtual ~Foo() {} 
    const int& Value() const {return mValue;} 
    template<int TDim> 
    bool Compare(const Foo& rother_foo) {return Foo_Helper<TDim>::Compare(*this, rother_foo);} 
private: 
    int mValue; 
}; 

#endif 

#include "foo.hpp" 

foo.hpp die Vorlage Spezialisierung zu definieren:

#ifndef FOO_HPP_INCLUDED 
#define FOO_HPP_INCLUDED 

template<> 
bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo) 
{ 
    return this_foo.Value() == other_foo.Value(); 
} 

template<> 
bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo) 
{ 
    return this_foo.Value() == other_foo.Value(); 
} 

#endif 

die beiden Quelldateien: src1.cpp:

#include "foo.h" 

class Test1 
{ 
public: 
    bool test() 
    { 
     Foo f1(1); 
     Foo f2(2); 

     return f1.Compare<1>(f2); 
    } 
}; 

src2.cpp:

#include "foo.h" 

class Test2 
{ 
public: 
    bool test() 
    { 
     Foo f1(1); 
     Foo f2(2); 

     return f1.Compare<2>(f2); 
    } 
}; 

CMakeLists.txt:

set(file_list 
src1.cpp 
src2.cpp 
) 

add_library(Test SHARED ${file_list}) 

Der Fehler messsage:

Linking CXX shared library libTest.so 
CMakeFiles/Test.dir/src2.cpp.o: In function `Foo_Helper<1>::Compare(Foo const&, Foo const&)': 
/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:7: multiple definition of `Foo_Helper<1>::Compare(Foo const&, Foo const&)' 
CMakeFiles/Test.dir/src1.cpp.o:/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:7: first defined here 
CMakeFiles/Test.dir/src2.cpp.o: In function `Foo_Helper<2>::Compare(Foo const&, Foo const&)': 
/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:13: multiple definition of `Foo_Helper<2>::Compare(Foo const&, Foo const&)' 
CMakeFiles/Test.dir/src1.cpp.o:/home/hbui/workspace/c++/multiple_definition_error/foo.hpp:13: first defined here 
collect2: error: ld returned 1 exit status 
make[2]: *** [multiple_definition_error/libTest.so] Error 1 
make[1]: *** [multiple_definition_error/CMakeFiles/Test.dir/all] Error 2 
make: *** [all] Error 2 

ich die Aufnahme Wache gedacht hat verhindert die beiden Funktionen in foo.hpp wird kompiliert. Es sieht jedoch so aus, dass jede cpp-Datei ihre eigenen Funktionen kompiliert. Wie definiert man in diesem Fall die Template-Funktionen richtig?

+0

Sie verbindet verwirrend mit dem Kompilieren. Die Header-Wächter verhindern, dass der Compiler (der auf eine einzelne cpp -> -Objektkonvertierung schaut) mehrere Definitionen findet. Der Linker (der mehrere Objekte akzeptiert -> lib/exe) versucht, alle Funktionen zusammenzufügen. – UKMonkey

+0

Ja, aber was ist die Lösung? – kstn

+0

Nebenbei: Warum haben Sie zwei Spezialisierungen Ihrer Vorlage, die identische Körper haben? Was passiert, wenn jemand 'Foo :: Compare <3>' aufruft? – Caleth

Antwort

1

Die Header-Wächter verhindern, dass der Header zweimal in derselben Übersetzungseinheit enthalten ist. Ihr Problem ist, dass die Definitionen der Compare Spezialisierungen in zwei Übersetzungseinheiten definiert werden, aber nicht inline markiert sind. Das bedeutet, wenn der Linker versucht, die von test1.cpp und test2.cpp erzeugten Objektdateien zu verknüpfen, erhalten Sie einen Fehler mit mehreren Definitionen. Wenn Sie die Spezialisierungen als inline markieren, dann können sie in zwei TUs definiert werden und der Linker nur wegzuwerfen eine der Definitionen:

template<> 
inline bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo) 
//^^^^ 
{ 
    return this_foo.Value() == other_foo.Value(); 
} 

template<> 
inline bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo) 
//^^^^ 
{ 
    return this_foo.Value() == other_foo.Value(); 
} 
+0

Ah, das ist cool. Jetzt hab ich es verstanden. Inline bewirkt, dass die TU separat kompiliert wird.Wahrscheinlich ist mehr Kompilation gemacht, aber es hat das Problem gelöst. – kstn

0

Sie können auch Spezialisierung Code in CPP setzen. Ich denke, dass dies die beste Lösung ist, da die Spezialisierung (normalerweise) eng mit den neu erstellten Klassen (Test1 und Test2) zusammenhängt.

setzen Alternativ

template<> 
bool Foo_Helper<1>::Compare(const Foo& this_foo, const Foo& other_foo) 
{ 
    return this_foo.Value() == other_foo.Value(); 
} 

template<> 
bool Foo_Helper<2>::Compare(const Foo& this_foo, const Foo& other_foo) 
{ 
    return this_foo.Value() == other_foo.Value(); 
} 

in foo.cpp (statt foo.hpp) und in foo.hpp nur sagen, dass Spezialisierung ist "extern".

Zusätzlich sollten Sie Klassendeklarationen von src1.cpp zu src1.hpp bewegen;)

Verwandte Themen