2017-07-27 66 views
2

我有一個GCC 5.4.0連接器很奇怪的問題。我有這些文件:Header-only class +未定義的引用僅用於返回該類的對象

spline.hutils.h/cppmain.cpp

spline.h是擬合點花鍵只有頭的實用程序類。

1)我創建一個帶有utils.cpp和CMake的:

add_library(utils_lib utils.cpp) 

utils.h#include荷蘭國際集團spline.h

2)我從main.cpp創建我的二進制:

add_executable(hello_world main.cpp) 
target_link_libraries(hello_world utils_lib) 

3)內部utils.cpp,我有這樣的功能:

tk::spline fitSpline(const std::vector<double>& x, 
        const std::vector<double>& y) 
{ 
    tk::spline output; 
    output.set_points(x,y); 
    return output; 
} 

所以,如果我嘗試使用內main.cpp此功能:

auto my_spline = fitSpline(x,y); 

然後我得到這個鏈接錯誤:

undefined reference to `fitSpline(std::vector<double, std::allocator<double> > const&, std::vector<double, std::allocator<double> > const&)' 

但是如果我的fitSpline返回值更改爲double例如:

double fitSpline(const std::vector<double>& x, 
       const std::vector<double>& y) 
{ 
    tk::spline output; 
    output.set_points(x,y); 

    return 0.0; 
} 

然後,我沒有得到鏈接錯誤了!它編譯得很好。我真的不明白問題是什麼,有什麼提示?

謝謝!

+0

「utils.h」中是否存在'fitSpline'的現有函數簽名?只有我現在可以考慮的事情。如果可能的話,在'utils。*'和'main.cpp'中發佈相關的代碼。 – hnefatl

+0

@hnefatl是的,簽名就在那裏。正如我所說,如果我只是改變返回值類型,一切正常。 我剛剛意識到'spline.h'擁有匿名命名空間中的所有內容,當然這肯定是原因!我需要在每個cpp文件中包含它嗎? – user1011113

+0

如果它們確實在[匿名命名空間](https://stackoverflow.com/questions/154469/unnamed-anonymous-namespaces-vs-static-functions)中,那麼文件外部沒有任何內容可以訪問它們。 通過簽名,我的意思是問你是否有一個拆分定義和函數的實現,並忘記更新其中之一。在'main.cpp'中包含'spline.h'可能會有所幫助,但我真的不知道爲什麼會這樣。發佈更多的代碼會有所幫助。 – hnefatl

回答

0

有兩個翻譯單元。 TU爲utils_lib,TU爲main.cpp

未命名名稱空間中的名稱都位於唯一名稱空間中,並且實際上具有內部鏈接(因爲C++ 11中它們被定義爲具有內部鏈接)。

因此,嘗試引用來自不同TU的類型如tk::spline將因內部鏈接有效而失敗。

如果對象是無狀態的並且不共享,則重複使用spline.h通常會很好。但在這裏你沒有這樣做。通過在一個TU中創建一個對象並嘗試通過不同的TU中的類型來存儲它們,您將它們視爲可互換的。這將失敗,因爲它們具有不同的唯一名稱空間名稱。

如果您真的不想在僅包含標頭的庫中導出不必要的符號,則應該只對這些符號使用內部「詳細」名稱空間,而將外部名稱空間中用戶應該知道的那些符號。

沒有一個,順便說一句,與cmake或任何構建系統都有關係。然而,因爲你的問題使用cmake來使結構更清晰(好btw),標籤可能很好。

相關問題