【发布时间】:2012-03-20 22:34:44
【问题描述】:
我有一组函数,我在这样的标题中声明:
actual_function.hpp
#ifndef ACTUAL_FUNCTION_HPP
#define ACTUAL_FUNCTION_HPP
#include <iostream>
#ifdef CONDITION
#warning Compiling version 1
template<typename T>
T fun (T x) {
std::cout << "Version 1 implementation is called.\n";
return x + x;
}
#else
#warning Compiling version 2
template<typename T>
T fun (T x) {
std::cout << "Version 2 implementation is called.\n";
return 2 * x + 1;
}
#endif
#endif
我正在尝试在一个测试程序中测试该功能的两个版本。我认为我可以使用多个翻译单元来做到这一点,所以我有一个这样的文件布局:
main.cpp:
void test_version_1 ();
void test_version_2 ();
int main () {
test_version_1 ();
test_version_2 ();
return 0;
}
test1.cpp:
#include <cassert>
#include <iostream>
#define CONDITION
#include "actual_function.hpp"
void test_version_1 () {
std::cout << "Version 1 is called.\n";
assert (fun (8) == 16);
}
test2.cpp
#include <cassert>
#include <iostream>
#undef CONDITION
#include "actual_function.hpp"
void test_version_2 () {
std::cout << "Version 2 is called.\n";
assert (fun (8) == 17);
}
我的想法是,这会给 test1.cpp 版本 1 带来乐趣,而 test2.cpp 版本 2 带来乐趣。预处理器的输出似乎支持这个想法:
g++ main.cpp test1.cpp test2.cpp
In file included from test1.cpp:4:0:
actual_function.hpp:7:2: warning: #warning Compiling version 1 [-Wcpp]
In file included from test2.cpp:4:0:
actual_function.hpp:14:2: warning: #warning Compiling version 2 [-Wcpp]
但是,我的猜测是链接器在我身上搞混了。当我运行程序时,会发生以下情况:
./a.out
Version 1 is called.
Version 1 implementation is called.
Version 2 is called.
Version 1 implementation is called.
a.out: test2.cpp:7: void test_version_2(): Assertion `fun (8) == 17' failed.
Aborted (core dumped)
如果我仅在其中一个定义中将 fun 重命名为其他名称,并调用该新命名的函数,则一切都按预期工作,这表明正确的函数在正确的位置可见。如果我只在定义处重命名函数,但不更改调用点,则会收到编译器错误test2.cpp:7:2: error: ‘fun’ was not declared in this scope。这让我认为链接器正在覆盖函数,因为它们具有相同的名称和签名。
真的是这样吗?如果是这样,最好的解决方案是什么?我的两个想法如下:
1:让我的函数接受一个额外的模板参数,所以它会是模板,然后专注于真与假。实际上,我可能需要比这更复杂的东西(也许专门研究 int 或其他东西),因为我真正的问题有更多选择。如果定义了 CONDITION 宏,则它使用手动版本。如果未定义条件宏,那么它会查看它是否知道任何编译器内在函数可以手动执行我所做的操作,如果是,则使用它们,否则,无论宏是否存在,它都会退回到手动定义。不过,某种模板专业化仍然可以在这里工作。
2:创建具有不同名称fun_manual 和fun_intrinsic 的函数,并让fun 成为根据名称调用它们的包装函数。我不完全确定这将如何工作。
我主要担心的是,如果编译器不支持内在版本,则编译器看不到内在版本,否则会报错。
我的两个解决方案是我能做的最好的,还是有更好的?
【问题讨论】:
-
如果不是所有翻译单元都看到完全相同的定义,这是未定义的行为。
-
你有函数模板,而不是函数。
-
GCC 中是否有一个警告可以打开来提醒用户多个功能正在合并为一个?修复我的
actual_function.hpp标头后,我仍然得到相同的错误结果。然后我意识到在我的代码的另一部分中,我忘记在未命名的命名空间中粘贴一些函数。
标签: c++ linker c-preprocessor