1

我正在使用一个开源库,它提供了一个 .hpp 文件,其中定义了几个静态函数,如下面的代码。

当我在我的项目中两次包含这个文件时,我总是得到一个链接器错误,抱怨重复的符号。我很清楚函数被定义了两次,但我不知道如何解决这个问题。我曾尝试将函数标记为外部或内联但没有成功。

解决此问题的最佳方法是什么?

#ifndef OPENMVG_ROBUST_ESTIMATOR_ACRANSAC_H_
#define OPENMVG_ROBUST_ESTIMATOR_ACRANSAC_H_

#include <algorithm>
#include <cmath>
#include <iterator>
#include <vector>
#include <limits>
#include <iostream>

#include "openMVG/robust_estimation/rand_sampling.hpp"

namespace openMVG {
namespace robust{

static double logcombi(size_t k, size_t n)
{...}

...

编辑:我忘了说还有模板功能,这意味着我不能使用 .h 和 .cpp 文件。这就是他们使用 .hpp 文件的原因。在这个页面(http://www.cplusplus.com/doc/tutorial/templates/)的底部,它说链接器在这种情况下不应该产生错误。我使用 Xcode 作为标准设置的 IDE。显然这里有问题。链接器错误如下所示:

duplicate symbol __ZN7openMVG6robust13UniformSampleEmmPSt6vectorImSaImEE in:
    /Users/chris/Library/Developer/Xcode/DerivedData/SfM_OpenMVG-dgkssozpvorbpphdefdpurfpdaqv/Build/Intermediates/SfM_OpenMVG.build/Debug/SfM_incremental_unified.build/Objects-normal/x86_64/SfMIncrementalEngine.o
    /Users/chris/Library/Developer/Xcode/DerivedData/SfM_OpenMVG-dgkssozpvorbpphdefdpurfpdaqv/Build/Intermediates/SfM_OpenMVG.build/Debug/SfM_incremental_unified.build/Objects-normal/x86_64/computeMatches.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

解决方案:事实证明,我所指的 hpp 文件包含一个文件,该文件定义了一个与原始文件中的一个函数同名的函数,这就是导致链接器错误的原因。我不知道为什么在仅包含一次 .hpp 文件时这甚至会首先起作用。

4

3 回答 3

0

据我所知,您在声明它们的同一个地方实现这些功能。这是双重包含错误的原因。到目前为止,您有两种选择:

  1. 按照Bathsheba的建议使用“内联”子句。问题是:“内联”只是一个提示。编译器可能会拒绝您对函数进行内联的尝试,即使询问了“forceinline”。看来,您的案例不是内联兼容的,因为它对您没有帮助。
  2. 像往常一样拆分函数 .H + .CPP 对,以便客户端代码包含 .H 文件,然后链接到包含 .CPP 的库

您将文件命名为 .HPP 而不是 .H 的事实与编译器处理它的方式无关。您可以对文件使用任意扩展名,然后将其作为标题包含在内。因此,这里的命名约定只不过是良好的编程风格(.H 用于 C/C++ 兼容的头文件,.HPP 仅用于 C++)。

于 2013-05-28T22:36:13.247 回答
0

我知道你说你已经这样做了,但是替换

static double logcombi(size_t k, size_t n)

inline double logcombi(size_t k, size_t n)

完全重新编译。

于 2013-05-28T15:10:24.160 回答
0

在标题中分发您的库是一件非常奇怪的事情。由于您可以访问源代码,我只需创建相应的 cpp 文件,将代码从标头复制并粘贴到 cpp 文件,然后删除标头中的函数主体。

我还将从标题中删除静态函数:在您希望在其中找到可导出符号(即公共函数)的文件中具有静态(私有)函数实际上没有多大意义。

最后,您确定该 hpp 文件中只有函数吗?如果有常数,那同样会有问题。在这种情况下,我会在标头中保留带有 extern 的声明,并将常量移动到 cpp 文件中。

我知道,这是很多工作(嗯,实际上并没有那么多),但它也是安排事情的唯一明智方式。

希望这可以帮助。

于 2013-05-28T15:18:16.403 回答