例如,从我对C ++和clang ++的基本了解,我不明白为什么以下设置不受欢迎:
似乎在标头中使用变体会产生更多输出,需要更特定的编译器设置,并且在函数声明中需要重复。
clang++ --std=c++2a Start.cpp -o Start.o; ./Start.o
Start.cpp
#include "A.cpp"
#include "B.cpp"
int main (
int argc,
char** argv
) {
A();
B();
return 0;
}
A.cpp
#ifndef A_H
#define A_H
#include <stdio.h>
#include "C.cpp"
void A() {
printf("A\n");
C();
}
#endif
B.cpp
#ifndef B_H
#define B_H
#include <stdio.h>
#include "C.cpp"
void B() {
printf("B\n");
C();
}
#endif
C.cpp
#ifndef C_H
#define C_H
#include <stdio.h>
void C() {
printf("C\n");
}
#endif
而且,通常会编译cpp文件并将它们链接在一起。如果您既编译这些cpp文件中的任何一个,同时又将其包含到另一个转换单元中,则将遇到违反ODR的情况。
为了解决此问题,如果您将一个文件包含在其他文件中,那么通常应确保所包含的文件(即头文件)不包含任何包含在多个翻译单元中的违反ODR的内容。
此外,遵循常用的命名方案也是一种最佳实践。对头文件使用cpp扩展名与所有常见的命名方案相反。
是否有充分的理由在h文件而不是cpp文件中使用包含防护?
无论您如何命名头文件,都应始终在所有头文件中使用include guard。 (尽管从技术上讲,在某些标头中不需要标头保护,但是简单地使用标头保护比跟踪是否需要它更容易)。
单个TU的优点:由于没有重复编译模板和其他内联函数,因此从头开始的编译时间更快。另外,由于没有翻译单元边界会妨碍优化,因此优化效果也更好-跨TU边界工作的链接时间优化削弱了这一优势。
缺点:对程序的任何更改只会导致重新编译修改的翻译单元。如果只有一个翻译单元是整个程序,那么任何更改,无论大小如何,都将需要重新编译整个程序。这是非常不希望的。链接时间优化可消除此缺点,链接时间优化可导致链接太慢,以至于从重用翻译单元节省的时间变得微不足道。