2017-03-13 20 views
2

ASSERT_EQが以下の理由でundefined reference to Bar::kBarエラーを引き起こすのはなぜですか?gtestで未定義の参照

コンパイルする: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

私の答えからわかるように、あなたの質問は実際にはC++に関するもので、ちょうど というのはちょっとだけグーグレストに関係しています。言語タグを追加することを検討してください。 –

+0

@MikeKinghan答えをありがとう! –

答えて

6

をGoogletestよくある質問から:

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

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

あなたのクラスには、静的データメンバを持っている場合

またfoo.ccでクラス本体の外側で、それを定義する必要があります。

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

そうでなければ、あなたのコードは無効C++で、予期しない方法で破損する可能性があります。 特に、Google Test比較アサーション(EXPECT_EQなど)で使用すると、 は "未定義の参照"リンカエラーを生成します。

この説明はかなり謎です。 (なぜ「無効なC++?」)それはおそらく です。満足できる説明はむしろ技術的なものですから。あなたのクラスbarは外部リンケージを持つ 定義とデータメンバーを提供するために十分ではない静的データメンバ 初期化子とkBarを、宣言していても

(つまり、リンカは見ることができる)、および1つのない odrを使用しようとするコード Bar::kBar は、定義されていない参照リンクエラーが発生します。これはGoogletestを介さず を示すことができる。

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

foobar.cppは、構築するために試してみてください。

$ 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 

ソリューションは、よくある質問のとおりです:

#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(); 
} 

C++ 17では、次のことが可能になります。 の場合、初期化されたクラス内宣言の先頭にinline( )と定義すると、クラス外の定義は省略されます。


[1] ODR-use

を非公式にそのアドレスが取られている場合、オブジェクトはODR-使用され、又は参照がそれに結合し であり、関数は、関数呼び出し場合ODR、使用されそれが行われたか、そのアドレス が取得されます。オブジェクトまたは関数がodr-usedである場合、その定義はプログラムのどこかにある でなければなりません。その違反はリンク時エラーです。