【问题标题】:C++, Clang: #including associated header with cpp does not compileC++,Clang:#include 与 cpp 关联的标头无法编译
【发布时间】:2018-02-20 15:26:00
【问题描述】:

我有一个main方法,

main.cpp:

#include "MyStruct.h"

MyStruct.h:

#ifndef MYPROJ_MYSTRUCT_H
#define MYPROJ_MYSTRUCT_H
#include <vector>
#include <unordered_map>

bool function1(std::vector<std::string> label){ 
    // actual implementation     
}
bool function2(...){ ... }

struct MyStruct{ ... }
#endif

这编译。但是,当我添加 cpp 文件以包含函数定义时,

main.cpp: 

#include "MyStruct.h"

MyStruct.h:

#ifndef MYPROJ_MYSTRUCT_H
#define MYPROJ_MYSTRUCT_H
#include <vector>

bool function1(...){ ... }
bool function2(...){ ... }

struct MyStruct{ ... }
#endif

MyStruct.cpp:

#include "MyStruct.h"

// and that's it

仅仅通过包含头文件,我就会得到链接器错误,就好像我多次导入头文件一样;

这里是 CMakeLists:

cmake_minimum_required(VERSION 3.8)
set(CMAKE_CXX_STANDARD 17)

set(SOURCE_FILES main.cpp MyStruct.cpp)
add_executable(my_proj ${SOURCE_FILES})

错误包括所有重复的符号错误。我不知道如何让它工作,因为这是我一直在使用 make 和 g++ 而没有遇到问题的事情;当我在 Cygwin/Windows 上使用 CMake 和 g++ 时,我似乎也没有这个问题(这是在 MacOSX 上)。


接下来,当我将所有函数转换为 .cpp 文件,并且只有声明出现在标头中时,我消除了大多数重复符号,除了:

duplicate symbol __Z8get_uvidv in:
    CMakeFiles/main.cpp.o
    CMakeFiles/MyStruct.cpp.o
duplicate symbol _uvid in:
    CMakeFiles/main.cpp.o
    CMakeFiles/MyStruct.cpp.o
ld: 2 duplicate symbols for architecture x86_64

更新源


// header: MyStruct.h

#ifndef MYPROJ_MYSTRUCT_H
#define MYPROJ_MYSTRUCT_H

#include <unordered_map>
#include <vector>
#include "AnotherStruct.h"

bool add_item(std::pair<std::string,float> & item);
void insert_item(std::vector<AnotherStruct> & A, std::pair<std::string,float> element);
...

struct MyStruct {
    std::unordered_map<std::string,int> labels;
    std::vector<AnotherStruct> data;

    MyStruct(std::vector<char *> inputs);

    void GetData();
    void SortData(bool (*compare)(AnotherStruct &,AnotherStruct &);
    //...
}
#endif

还有.cpp

#include "MyStruct.h"

// implement everything declared in .h 
bool add_item(...){
    ...
}
bool insert_item(...){
    ...
} 

MyStruct::MyStruct(...){
    ...
}
void MyStruct::GetData(...){
    ...
}
void MyStruct::SortData(...){
    ...
}

还有主要的:

#include "MyStruct.h"

错误:

duplicate symbol __Z8get_uvidv in: 
    main.cpp.o
    MyStruct.cpp.o
duplicate symbol _uvid in:
    main.cpp.o
    MyStruct.cpp.o

不知道__Z8get_uvidv 可能是什么,_uvid 也可能是什么,所以我认为std imports 或在编译器的底层发生了一些事情.

请记住,当我将所有内容复制到 main 方法或将所有定义保留在头文件中时,所有内容都会编译,我很难过。

【问题讨论】:

  • This answewr 回答了这个问题,但我不喜欢将 Q 用作欺骗目标。
  • 那些大括号让我觉得你的标题包含实际的函数定义而不仅仅是前向声明,这也与重复符号一致。
  • @bordeo 你的头文件不应该包含任何函数定义(例如int f() { return 1; })只有前向声明(例如int f();)除非那些是模板函数或者它们被标记为内联(在这种情况下你应该'不要在别处写他们的定义)。否则,当您在两个不同的文件中包含标头时,在不同的翻译单元(= cpp 文件,如果您愿意的话)中将有相同函数的两个定义,这会使链接器感到困惑。
  • 哦,顺便说一句,一个有趣的细节是在类范围内定义的函数被隐式标记为内联。因此,如果您在标头中有struct C { int method() { return 1; } };,包括它两次不会导致链接器出现问题(method 在此处被隐式标记为内联)。但是,您在标题中遇到struct C { int method(); }; int C::method() { return 1; } 的问题(假设它被包含两次),第二部分可能应该移动到一个 cpp 文件中。
  • 您包含的AnotherStruct.h,是您编写的还是来自某个第三方库?您是否确保它也不包含定义? (对于您直接或间接包含在AnotherStruct.h 中的任何其他标题也是如此)

标签: c++ compiler-errors compilation cmake


【解决方案1】:

您已将MyStruct.h 包含在main.cppMyStruct.cpp 中。

Include 基本上是复制粘贴,留下 2 个翻译单元(main.cppMyStruct.cpp),它们都包含 function1function2 的定义(因为你在两者中都包含了头文件)。

解决方案:

只在头文件中声明函数,只在一个翻译单元中定义。

【讨论】:

  • 嗯。我已经这样做了,然后走回去产生这个最小的步骤来打破它。是否有可能我的结构中的功能导致此错误,而不仅仅是我的函数?
  • @bordeo bool function1(...){ ... } in "MyStruct.h" 建议标头包含定义,这是错误的原因,这在此答案中进行了解释。但是,如果它不包含函数的定义 - 请编辑您的 minimal reproducible example,使其与您的代码匹配。
  • 是的。 @bordeo 按照惯例,使用头文件进行声明,使用 .cpp (或其他)进行实施。这将防止此错误。
  • @Major,嗯。是的,我就是这么想的。但是,最后两个重复符号错误:duplicate symbol __Z8get_uvidvduplicate symbol _uvid 在将所有内容转换到 .cpp 文件后似乎无法消除。
  • @bordeo 我不太习惯从符号中解密类型。你的程序中get_uviduvid(或类似的东西)的类型是什么?它们在您的标题中出现在哪里以及如何出现?
猜你喜欢
  • 1970-01-01
  • 2017-12-12
  • 2014-09-03
  • 1970-01-01
  • 2019-01-29
  • 1970-01-01
  • 2013-10-28
相关资源
最近更新 更多