2011-01-30 7 views
4

Я работаю над библиотекой C++ maths, в которой я хочу иметь возможность настраивать во время компиляции с помощью define.Использование #define для конфигурации библиотеки

Одна из конфигураций определяет точность. В коде это выглядит так:

#ifdef MYMATH_USE_DOUBLE 
    typedef double Real; 
#else 
    typedef float Real; 
#endif 

Это нормально работает.

Если кто-то хочет использовать библиотеку после того, как она была сконфигурирована с помощью MYMATH_USE_DOUBLE, они также должны передать это определение компилятору.

Есть ли лучший способ сделать это?

Я не хочу, чтобы пользователь помнил, какие определения были использованы для компиляции библиотек математики, а затем повторить их все для своего приложения.

ответ

1

Как правило, лучше всего запустить скрипт «configure», который создает один файл со всеми определениями. И этот файл включен во все заголовки. Например, если вы скомпилируете OpenSSL из источников, «configure» создает e_os.h (насколько помните имя), который включен практически в каждый заголовок.

+0

Это то, что я считал решением. Теперь мне просто нужно выяснить, имеет ли мой метод сборки (scons) способ создания заголовка. – m0tive

+0

Это отвечает на то, как компилировать предпочтения в библиотеку. Я согласен с тем, что использование шаблонов (описанных в других комментариях) также будет работать, но требует большего количества рефакторинга кода. – m0tive

2

Предоставьте два параллельных набора функций, один для реализации с использованием float, а другой для реализации с использованием double (и третий для long double). Это то, что делает библиотека C - есть sin() для double, sinf() для float и sinl() для long double.

Или, на C++, вы могли бы (возможно, должны?) Рассмотреть возможность использования перегрузок или шаблонов. Мое подозрение в том, что это Это может привести к путанице, а не простоте (или, в основном, она будет использовать перегрузки double, поскольку литералы с плавающей запятой - double, если они явно не указаны), но шаблоны часто являются методом выбора этих дней.

(Комментарии изменены в свете замечаний bstamour; я был слишком консервативен и 1990-е-иш.)

+0

Поскольку это C++, вы можете также использовать шаблоны, так как проблема такого типа заключается в том, что они предназначены для решения. Кроме того, система шаблонов может вызывать шаблонный тип в зависимости от типа переданного параметра, поэтому он не должен приводить к путанице с точки зрения пользователей. – bstamour

2

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

template <typename F = double> 
F sin(const F& r) 
{ 
//... 
} 

Тем путем пользователи могут использовать функции как для двойников, но они имеют возможность изменить тип:

float f = sin<float>(r); 

EDIT: Система шаблонов должна автоматически сделать вывод, что F является поплавок в этом случае, хотя, если r является поплавком.

+0

Приятная часть использования шаблонов заключается в том, что он также позволяет пользователю библиотеки использовать настраиваемые типы плавающих для ваших функций. – bstamour

+0

Я бы использовал шаблоны (это решает проблему), но у меня есть проблемы с их использованием на базовых классах в библиотеке. Я делаю матрицу/quat/vector для 3D-приложений. Я стараюсь избегать использования шаблонов шаблонов, таких как классы матрицы 4x4, которые теоретически будут использоваться _alot_. – m0tive

+0

Почему вы избегаете шаблонов этих классов? Если вы убедитесь, что функции принимают ссылки const, вы все равно генерируете эффективный код. Если вы делаете какие-то тяжелые преобразования матриц, то передача их путем ссылки (независимо от типа) была бы хорошей идеей. – bstamour

0

Поместите условное определение в заголовочные файлы вашего lin (если его еще нет), а затем добавьте директиву для компилятора в соответствующий lib-файл вдоль него (когда он включен клиентами).

#ifdef MYMATH_USE_DOUBLE 
    typedef double Real; 
$ifndef _LIB // only for clients 
#pragma comment(lib, "double_lib") // double_lib name of the library. 
#endif 
#else 
    typedef float Real; 
$ifndef _LIB 
#pragma comment(lib, "float_lib") 
#endif 
#endif 
1

Как и другие опросы, использование шаблонов является возможным решением вашей проблемы. Однако, если вы публикуете свой общий код для пользователей, им придется перекомпилировать вашу библиотеку при выборе другого типа.Это могло бы иметь больше смысла использовать только общий код внутренне и подвергать интерфейс с фиксированным набором типов с использованием набившие оскомины перегрузки функции:

// generic implementation (internal linkage): 
namespace { 
    template<typename Real> 
    Real plus42(Real value) { 
     return value + 42; 
    } 
} 

// API functions (external linkage): 
float plus42(float value) { return plus42<>(value); } 
double plus42(double value) { return plus42<>(value); } 

Допуская набор инструментов GNU, вы должны быть в состоянии избежать вытягивать в мертвой коде при связывании статически путем передачи -fvtable-gc -ffunction-sections -fdata-sections компилятору и -Wl,--gc-sections в компоновщик.

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