У меня есть набор функций, которые я объявляю в заголовке следующим образом:
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: Пусть мои функции принимают дополнительный аргумент шаблона, чтобы он был шаблоном, а затем специализировался на значениях true и false.В действительности мне, вероятно, понадобится что-то более сложное, чем это (возможно, специализирующееся на int или чем-то еще), потому что у моей настоящей проблемы есть еще несколько вариантов.Если макрос CONDITION определен, он использует ручную версию.Если макрос условия не определен, то он видит, знает ли он о каких-либо встроенных функциях компилятора, которые делают то, что я делаю вручную, и, если это так, он использует их, в противном случае он прибегает к ручным определениям независимо от наличия макроса.Тем не менее, некоторая специализация шаблонов может работать и здесь.
2: создавать функции с разными именами fun_manual
и fun_intrinsic
и иметь fun
функцию-обертку, которая вызывает их на основе их имени.Я не совсем уверен, как это будет работать.
Моя основная проблема заключается в том, что если компилятор не поддерживает встроенную версию, встроенная версия не будет видна компилятору, или это приведет к ошибке.
Одно из моих двух решений лучшее, что я могу сделать, или есть что-то лучшее?