2017-07-27 70 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),标签可能很好。

相关问题