2015-06-04 6 views
6

Предположим, есть библиотека, одна из которых определяет функцию с именем foo, а другая версия имеет имя, измененное на foo_other, но обе эти функции все еще имеют те же аргументы и возвращаемые значения. Я в настоящее время использую условную компиляцию, как это:Есть ли способ проверить, была ли функция объявлена?

#include <foo.h> 
#ifdef USE_NEW_FOO 
#define trueFoo foo_other 
#else 
#define trueFoo foo 
#endif 

Но это требует какого-то внешнего обнаружения версии библиотеки и установив соответствующий параметр компилятора, как -DUSE_NEW_FOO. Я бы предпочел, чтобы код автоматически определял, какую функцию он должен вызывать, исходя из того, что он объявлен или нет в <foo.h>.

Есть ли способ достичь этого в любой версии C?

Если нет, переключится ли на любую версию C++ какие-либо способы сделать это? (при условии, что библиотека выполняет все необходимые действия, например, extern "C" блоков в своих заголовках)? А именно, я думаю о том, чтобы каким-то образом использовать SFINAE, но для глобальной функции, а не метода, которая обсуждалась в связанном вопросе.

+0

с gcc ... может быть что-то вроде 'prototype ... foo ... __attribute__ ((alias (" foo_other ")));' ... см. Https://gcc.gnu.org/onlinedocs/gcc /Common-Function-Attributes.html – pmg

+0

Это дубликат http://stackoverflow.com/questions/1749233/check-whether-function-is-declared-with-c-preprocessor –

+0

@BrianSidebotham нет, это не так. Я не указал, что нужно использовать препроцессор. Также я прошу об альтернативных способах перехода на C++. – Ruslan

ответ

4

В C++ вы можете использовать выражение SFINAE для этого:

//this template only enabled if foo is declared with the right args 
template <typename... Args> 
auto trueFoo (Args&&... args) -> decltype(foo(std::forward<Args>(args)...)) 
{ 
    return foo(std::forward<Args>(args)...); 
} 

//ditto for fooOther 
template <typename... Args> 
auto trueFoo (Args&&... args) -> decltype(fooOther(std::forward<Args>(args)...)) 
{ 
    return fooOther(std::forward<Args>(args)...); 
} 
0

Если вы используете static, ссылаясь на функцию, в большинстве версий C++ имя функции «искажено», чтобы отразить список аргументов. Поэтому попытка статически Ссылка на библиотеку, с программой с устаревшим файлом .hpp приведет к ошибке компоновщика «неизвестного символа».

На языке C нет никаких метаданных любого типа, которые указывают, что список аргументов любой экспортируемой функции фактически есть.

Реально, я думаю, вы просто должны быть уверены, что .h или .hpp файлы, которые вы используете для ссылки на библиотеки, на самом деле отражают соответствующий объект-код в любой версии этой библиотеки вы используете , Вы также должны быть уверены, что процесс Makefile (или «авто-make») будет правильно идентифицировать все-все модули в вашем приложении, которые ссылаются на эту библиотеку и которые поэтому должны быть перекомпилированы в случае каких-либо изменений в нем. (Если бы это был я, я бы перекомпилировал все приложение.) Короче говоря, вы должны следить за тем, чтобы эта проблема не возникала.

+0

Как я уже отмечал после связанной с C++ части вопроса, предположим, что функция объявлена ​​в блоке '' extern '', поэтому имя не будет искажено. – Ruslan

+0

Да, действительно. И, если имя «не искажено», компоновщик не сможет узнать, действительно ли фактический двоичный код, к которому он (успешно) связывает ваш код, фактически соответствует файлу '.h' или' .hpp', который вы использовали при компиляции. И это невозможно. Реально, я думаю, что это точно так же, как то, что вас окружает, если изменится смысл существующей внешней подпрограммы: * вы должны быть тем, кто должен придерживаться таких вещей. –

0

В C++ вы можете сделать что-то вроде этого:

#include <iostream> 
#include <type_traits> 

//#define DEFINE_F 

#ifdef DEFINE_F 
void f() 
{ 

} 
#endif 

namespace 
{ 
    constexpr struct special 
    { 
     std::false_type operator()() const; 
    }f; 
} 

struct checkForF 
{ 
    static const constexpr auto value = std::conditional< std::is_same<std::false_type, decltype(::f())>::value, std::false_type, std::true_type >::type(); 
}; 

int main() 
{ 
    std::cout << checkForF::value << std::endl; 
} 

ideone

Пожалуйста, обратите внимание, я только обрабатывать е без каких-либо параметры.

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