2012-03-20 3 views
0

У меня есть набор функций, которые я объявляю в заголовке, как это:Несколько функций с тем же именем и подписью, переписывающие друг друга?

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 - функцию-оболочку, которая вызывает их на основе их имени. Я не совсем уверен, как это сработает.

Моя основная проблема заключается в том, что если компилятор не поддерживает внутреннюю версию, внутренняя версия не может быть замечена компилятором или она даст ошибку.

Являются ли какие-либо из моих двух решений лучшими, что я могу сделать, или есть что-то лучше?

+1

Это не определено поведение, если не все единицы перевода отображают точно такие же определения. –

+2

У вас есть функциональные шаблоны, а не функции. –

+0

Есть ли предупреждение в GCC, которое можно включить, чтобы предупредить пользователя о том, что несколько функций объединяются в один? После исправления заголовка 'actual_function.hpp', я все равно получил те же ошибочные результаты. Затем я понял, что в другой части моего кода я забыл использовать некоторые функции в неназванном пространстве имен. –

ответ

5

Вы нарушаете One Definition Rule. По сути, комбинация компилятора и компоновщика позволяет обрабатывать разные версии функции, как если бы они были одинаковыми.

0

Мое окончательное решение последовало моя идея # 2, и выглядит примерно так:

#undef NO_INTRINSICS 
#undef FUNCTION 
// INTRINSIC_VERSION_?_EXISTS are a set of conditional statements that are 
// defined by my environment 
#if INTRINSIC_VERSION_X_EXISTS 
    #define FUNCTION INTRINSIC_FUNCTION_X 
#elif INTRINSIC_VERSION_Y_EXISTS 
    #define FUNCTION INTRINSIC_FUNCTION_Y 
#else 
    #define NO_INTRINSICS 
#endif 

template<typename T> 
T manual_function (T x) { 
    // implementation 
} 
// Compilation will fail if the user requests intrinsic versions but none 
// exist. 
template<typename T> 
T intrinsic_function (T x) { 
    return FUNCTION (x); 
} 
template<typename T> 
T function (T x) { 
    #if defined NO_INTRINSICS 
     return manual_function (x); 
    #else 
     return intrinsic_function (x); 
    #endif 
} 

#undef FUNCTION 
#undef NO_INTRINSICS 

Это позволяет мне проверить вручную и внутренние версии своих функций. Тем не менее, не всегда доступны внутренние версии, поэтому пользователь может безопасно вызывать функцию, которая будет выбирать внутреннюю версию, если она существует (для скорости), в противном случае отпадает в ручной версии (для переносимости).

Я тестирую версию вручную, просто называя manual_function. Я тестирую внутреннюю версию, вызывая функцию (поэтому нет ошибок компиляции, если на этой конкретной платформе нет встроенных версий). Очевидно, что если нет встроенных версий, я не тестирую ничего нового, вызывая функцию, но это потому, что ничего не остается, чтобы проверить, что означает, что мои тесты по-прежнему имеют полный охват.

Смежные вопросы