2017-03-13 4 views
2

Warum verursacht der ASSERT_EQ einen Fehler ?Nicht definierte Referenz mit gtest

zu kompilieren: g++ a.cc -lgtest -lpthread

#include <gtest/gtest.h> 

class Bar { 
public: 
    static const size_t kBar = 0; 
}; 

TEST(Basic, Basic) { 
    ASSERT_EQ(0, Bar::kBar); 
} 

int main(int argc, char **argv) { 
    testing::InitGoogleTest(&argc, argv); 
    return RUN_ALL_TESTS(); 
} 
+1

Wie Sie aus meiner Antwort sehen, ist Ihre Frage wirklich über C++ und nur betrifft übrigens Googeltest. Erwägen Sie, das Sprach-Tag hinzuzufügen. –

+0

@MikeKinghan Danke für die Antwort! –

Antwort

6

Vom Googletest FAQ:

The compiler complains about "undefined references" to some static const member variables, but I did define them in the class body.

Wenn Ihre Klasse ein statisches Datenelement hat:

// foo.h 
class Foo { 
    ... 
    static const int kBar = 100; 
}; 

Sie müssen es auch außerhalb der Klasse Körper in foo.cc definieren:

const int Foo::kBar; // No initializer here. 

Andernfalls wird Ihr Code ungültig C++, und brechen auf unerwartete Weise. Insbesondere wird die Verwendung von Google Test-Vergleichs-Assertions (EXPECT_EQ usw.) einen Linkfehler "undefinierter Referenz" erzeugen.

Diese Erklärung ist ziemlich rätselhaft. (Warum ist es "ungültig C++?") Das ist wahrscheinlich, weil eine zufriedenstellende Erklärung eher technisch ist.

Auch wenn Ihre Klasse bar deklariert die statische Daten Mitglied kBar mit ein initializer, die nicht das Datenelement mit einer Definition bereitzustellen genügt, die externe Bindung hat (dh dass der Linker sehen) und ohne ein Jeder Code, der versucht, Bar::kBar zu verwenden, wird einen undefinierten Referenz-Verknüpfungsfehler auftreten.

foobar.cpp

#include <cstdlib> 

class Bar { 
    public: 
    static const std::size_t kBar = 0; 
}; 

bool foo(std::size_t const & k) 
{ 
    return k == 0; 
} 

int main() 
{ 
    return foo(Bar::kBar); 
} 

Versuchen zu bauen: Das kann ohne Beteiligung Googletest dargestellt werden

$ g++ foobar.cpp 
/tmp/ccWaEsDu.o: In function `main': 
foobar.cpp:(.text+0x1c): undefined reference to `Bar::kBar' 
collect2: error: ld returned 1 exit status 

Die Lösung ist laut der FAQ:

#include <gtest/gtest.h> 

class Bar { 
    public: 
    static const size_t kBar = 0; 
}; 

const size_t Bar::kBar; 

TEST(Basic, Basic) { 
    ASSERT_EQ(0, Bar::kBar); 
} 

int main(int argc, char **argv) { 
    testing::InitGoogleTest(&argc, argv); 
    return RUN_ALL_TESTS(); 
} 

Ab C++ 17 können Sie die Präfix der initialisierten In-Klasse-Deklaration mit inline (die wird es eine Definition machen) weglassen.


[1] ODR-use

Informal, ein Objekt ist ODR-verwendet, wenn die Adresse aufgenommen wird, oder eine Referenz daran gebunden, und eine Funktion ist ODR-verwendet, wenn ein Funktionsaufruf dazu ist es gemacht oder seine Adresse ist vergeben.Wenn ein Objekt oder eine Funktion odr-used ist, muss seine Definition irgendwo im Programm existieren; Eine Verletzung davon ist ein Link-Zeit-Fehler.

Verwandte Themen