当 C++ 程序在两个地方定义时,如何阻止它从错误的源文件调用函数体?

How do I stop a C++ program from calling a function body from the wrong source file, when it's defined in 2 places?

我试过用同一函数的两个副本创建一个静态库,定义在两个单独的 header/source 文件中。 这 2 个源文件应该是互斥的,并且不能包含在同一文件中。 我用下面的示例代码重现了这个问题。 这是在 VS2019 上编写和测试的,我还没有在任何其他编译器上测试过。

以下是foobar静态库:

foo.h

#pragma once

#ifdef BAR
static_assert(-1, "Bar is already included, you shouldn't include both foo & bar");
#endif //BAR

#define FOO

void foobar();

foo.cpp

#include "foo.h"

#include <iostream>

void foobar(){
    std::cout << "this is foo!";
}

bar.h

#pragma once

#ifdef FOO
static_assert(-1, "Foo is already included, you shouldn't include both foo & bar");
#endif //FOO

#define BAR

void foobar();

bar.cpp

#include "bar.h"

#include <iostream>

void foobar(){
    std::cout << "this is bar!";
}

然后我可以用一个 main.cpp

创建一个可执行项目

我创建了这个文件的 3 个不同版本,但它们都打印同一行 "this is foo!" 以下是主文件的 3 个版本:

#include "bar.h"

int main() {
    foobar();
}
#include "foo.h"

int main() {
    foobar();
}
#include "foo.h"
#include "bar.h"

int main() {
    foobar();
}

所以我的问题是:

编辑:

非常感谢@selbie,你的回答很有用。我已经重写了它,这样它就不那么骇人听闻了。

foo.h

#pragma once

#ifdef BAR
static_assert(false, "Bar is already included, you shouldn't include both foo & bar");

#endif //BAR

#define FOO
#include "foobar.h"

bar.h

#pragma once

#ifdef FOO
static_assert(false, "Foo is already included, you shouldn't include both foo & bar");

#endif //FOO

#define BAR
#include "foobar.h"

foobar.h

#pragma once

void foobar_foo();
void foobar_bar();

inline void foobar() {
#ifdef FOO
    foobar_foo();
#endif // FOO
#ifdef BAR
    foobar_bar();
#endif // BAR
}

foobar.cpp

#include "foobar.h"

#include <iostream>

void foobar_foo() {
    std::cout << "this is foo!";
}

void foobar_bar() {
    std::cout << "this is bar!";
}

我很惊讶链接器没有就此向您发出警告。当它将最终的可执行程序链接在一起时,它将选择 foobar 实现之一并丢弃另一个。

预处理器破解。 foobar 定义为调用唯一函数名称的宏或内联函数。定义 foo.h 和 foo.cpp 如下所示:

foo.h

#pragma once

#ifdef BAR
static_assert(false, "Bar is already included, you shouldn't include both foo & bar");

#endif //BAR

#define FOO

void foobar_foo();

#ifndef FOOBAR_IMPL
inline void foobar() {foobar_foo();}
#endif

// OR
// #ifdef foobar
// #undef foobar
// #endif
// #define foobar foobar_foo

然后foo.cpp:

#define FOOBAR_IMPL // avoids the ODR issue that user17732522 called out in comments

#include "foo.h"

#include <iostream>

void foobar_foo(){
    std::cout << "this is foo!";
}

对 bar.h 和 bar.cpp 重复此模式。