У меня есть набор функций, которые я объявляю в заголовке, как это:Несколько функций с тем же именем и подписью, переписывающие друг друга?
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)
Если переименовать весело что-то еще только в одном из определений, и называем это вновь с именем функции, все работает, как и ожидалось, что показывает, что правильные функции видны в правильных местах. Если я только переименую функцию в определении, но не изменяю точку вызова, я получаю ошибку компилятора test2.cpp:7:2: error: ‘fun’ was not declared in this scope
. Это заставляет меня думать, что компоновщик переписывает функции, потому что они имеют одинаковое имя и подпись.
Действительно ли это происходит? Если да, то какое наилучшее решение? Мои две мысли таковы:
1: Пусть мои функции принимают дополнительный аргумент шаблона, поэтому он будет шаблоном, а затем специализируется на true vs. false. На самом деле мне, вероятно, понадобится нечто более сложное, чем это (возможно, специализируемся на int или что-то еще), потому что у моей реальной проблемы есть еще несколько вариантов. Если макрос CONDITION определен, он использует ручную версию. Если макрос условия не определен, тогда он видит, знает ли он о каких-либо внутренних свойствах компилятора, которые выполняют то, что я делаю вручную, и если это так, они их используют, в противном случае он возвращается к описанию вручную независимо от наличия макроса. Однако какая-то специализированная специализация может работать здесь.
2: Создайте функции с разными именами fun_manual
и fun_intrinsic
и получите fun
- функцию-оболочку, которая вызывает их на основе их имени. Я не совсем уверен, как это сработает.
Моя основная проблема заключается в том, что если компилятор не поддерживает внутреннюю версию, внутренняя версия не может быть замечена компилятором или она даст ошибку.
Являются ли какие-либо из моих двух решений лучшими, что я могу сделать, или есть что-то лучше?
Это не определено поведение, если не все единицы перевода отображают точно такие же определения. –
У вас есть функциональные шаблоны, а не функции. –
Есть ли предупреждение в GCC, которое можно включить, чтобы предупредить пользователя о том, что несколько функций объединяются в один? После исправления заголовка 'actual_function.hpp', я все равно получил те же ошибочные результаты. Затем я понял, что в другой части моего кода я забыл использовать некоторые функции в неназванном пространстве имен. –