Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Setting Policies at Namespace or Translation Unit Scope

Boost , Math Toolkit 2.5.0 , Policy Tutorial

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Иногда то, что вы хотите сделать, это просто изменить набор политик в рамках текущей области:Единственное, что вы не должны делать в этой ситуации, это использовать макросы конфигурации, так как это может привести к нарушениям «Правила одного определения». Вместо этого библиотека предоставляет пару макросов специально для этой цели.

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

Предположим, что мы хотим<C::foo()>вести себя совместимым образом и установить<::errno>на ошибку, а не бросать какие-либо исключения.

Мы начнем с включения необходимого заголовка для нашей функции:

#include <boost/math/special_functions.hpp>
//using boost::math::tgamma; // Not needed because using C::tgamma.

Откройте пространство имен C, которое мы будем использовать для наших функций, и определите тип политики, который мы хотим: в этом случае C-стиль, который устанавливает::errno и возвращает стандартное значение, а не выбрасывает исключения.

Любая политика, которую мы здесь не указываем, унаследует дефолты.

namespace C
{ // To hold our C-style policy.
  //using namespace boost::math::policies; or explicitly:
  using boost::math::policies::policy;
  using boost::math::policies::domain_error;
  using boost::math::policies::pole_error;
  using boost::math::policies::overflow_error;
  using boost::math::policies::evaluation_error;
  using boost::math::policies::errno_on_error;
  typedef policy<
     domain_error<errno_on_error>,
     pole_error<errno_on_error>,
     overflow_error<errno_on_error>,
     evaluation_error<errno_on_error>
  > c_policy;

Все, что нам нужно сделать сейчас, это вызвать BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS Макро, передающий нашу политику типа c_policy как единственный аргумент:

BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(c_policy)
} // close namespace C

Теперь у нас есть набор функций пересылки, определенных в пространстве имен C, которые выглядят примерно так:

template <class RealType>
inline typename boost::math::tools::promote_args<RT>::type
   tgamma(RT z)
{
   return boost::math::tgamma(z, c_policy());
}

Когда мы звоним<C::tgamma(z)>, мы действительно звоним<boost::math::tgamma(z, C::c_policy())>:

int main()
{
   errno = 0;
   cout << "Result of tgamma(30000) is: "
      << C::tgamma(30000) << endl; // Note using C::tgamma
   cout << "errno = " << errno << endl; // errno = 34
   cout << "Result of tgamma(-10) is: "
      << C::tgamma(-10) << endl;
   cout << "errno = " << errno << endl; // errno = 33, overwriting previous value of 34.
}

Какие выходы:

Result of C::tgamma(30000) is: 1.#INF
errno = 34
Result of C::tgamma(-10) is: 1.#QNAN
errno = 33

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

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

#include <boost/math/special_functions.hpp>
// using boost::math::tgamma; // Would create an ambiguity between
// 'double boost::math::tgamma<int>(T)' and
// 'double 'anonymous-namespace'::tgamma<int>(RT)'.
namespace mymath
{ // unnamed
using namespace boost::math::policies;
typedef policy<
   domain_error<errno_on_error>,
   pole_error<errno_on_error>,
   overflow_error<errno_on_error>,
   evaluation_error<errno_on_error>
> c_policy;
BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(c_policy)

Когда мы звоним<mymath::tgamma(z)>, мы действительно звоним<boost::math::tgamma(z, anonymous-namespace::c_policy())>.

} // close unnamed namespace
int main()
{
   errno = 0;
   cout << "Result of tgamma(30000) is: "
      << mymath::tgamma(30000) << endl;
      // tgamma in unnamed namespace in this translation unit (file) only.
   cout << "errno = " << errno << endl;
   cout << "Result of tgamma(-10) is: "
      << mymath::tgamma(-10) << endl;
   cout << "errno = " << errno << endl;
   // Default tgamma policy would throw an exception, and abort.
}

Политика обработки статистических распределений очень похожа, за исключением того, что в настоящее время макросистемы BOOST_MATH_DECLARE_DISTRIBUTIONS принимает два параметра: тип плавающей точки для использования и тип политики для применения. Например:

BOOST_MATH_DECLARE_DISTRIBUTIONS(double, mypolicy)

Результаты набора типдефов определяются следующим образом:

typedef boost::math::normal_distribution<double, mypolicy> normal;

Имя каждого типа DEF совпадает с именем шаблона класса распределения, но без суффикса «_distribution».

Предположим, что мы хотим, чтобы набор распределений вел себя следующим образом:

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

Начнем с включения необходимого заголовка для всех дистрибутивов:

#include <boost/math/distributions.hpp>

Откройте соответствующее пространство имен, назвав его<my_distributions>для наших дистрибутивов, и определите тип политики, который мы хотим. Любая политика, которую мы не указываем здесь, наследует дефолты:

namespace my_distributions
{
  using namespace boost::math::policies;
  // using boost::math::policies::errno_on_error; // etc.
  typedef policy<
     // return infinity and set errno rather than throw:
     overflow_error<errno_on_error>,
     // Don't promote double -> long double internally:
     promote_double<false>,
     // Return the closest integer result for discrete quantiles:
     discrete_quantile<integer_round_nearest>
  > my_policy;

Все, что нам нужно сделать сейчас, это вызвать BOOST_MATH_DECLARE_DISTRIBUTIONS макрос, проходящий тип плавающей точки<double>и типы политики<my_policy>в качестве аргументов:

BOOST_MATH_DECLARE_DISTRIBUTIONS(double, my_policy)
} // close namespace my_namespace

Теперь у нас есть набор типдефов, определенных в пространстве имен my_distributions, которые выглядят примерно так:

typedef boost::math::normal_distribution<double, my_policy> normal;
typedef boost::math::cauchy_distribution<double, my_policy> cauchy;
typedef boost::math::gamma_distribution<double, my_policy> gamma;
// etc

Поэтому, когда мы используем my_distributions::normal, мы действительно используем<boost::math::normal_distribution<double,my_policy>>:

int main()
{
   // Construct distribution with something we know will overflow
  // (using double rather than if promoted to long double):
   my_distributions::normal norm(10, 2);
   errno = 0;
   cout << "Result of quantile(norm, 0) is: "
      << quantile(norm, 0) << endl; // -infinity.
   cout << "errno = " << errno << endl;
   errno = 0;
   cout << "Result of quantile(norm, 1) is: "
      << quantile(norm, 1) << endl; // +infinity.
   cout << "errno = " << errno << endl;
   // Now try a discrete distribution.
   my_distributions::binomial binom(20, 0.25);
   cout << "Result of quantile(binom, 0.05) is: "
      << quantile(binom, 0.05) << endl; // To check we get integer results.
   cout << "Result of quantile(complement(binom, 0.05)) is: "
      << quantile(complement(binom, 0.05)) << endl;
}

Какие выходы:

Result of quantile(norm, 0) is: -1.#INF
errno = 34
Result of quantile(norm, 1) is: 1.#INF
errno = 34
Result of quantile(binom, 0.05) is: 1
Result of quantile(complement(binom, 0.05)) is: 8

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

[Note] Note

Существует важное ограничение: вы можете не использовать макросы BOOST_MATH_DECLARE_DISTRIBUTIONS и BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS.в одноимённом пространстве*, так как это создает двусмысленности между функциями и распределениями одного и того же имени.

Как и прежде, этот же механизм хорошо работает в области файлов: используя неназванное пространство имен, мы можем гарантировать, что эти декларации не противоречат каким-либо альтернативным политикам, присутствующим в других единицах перевода:

#include <boost/math/distributions.hpp> // All distributions.
// using boost::math::normal; // Would create an ambguity between
// boost::math::normal_distribution<RealType> boost::math::normal and
// 'anonymous-namespace'::normal'.
namespace
{ // anonymous or unnnamed (rather than named as in policy_eg_6.cpp).
  using namespace boost::math::policies;
   // using boost::math::policies::errno_on_error; // etc.
  typedef policy<
     // return infinity and set errno rather than throw:
     overflow_error<errno_on_error>,
     // Don't promote double -> long double internally:
     promote_double<false>,
     // Return the closest integer result for discrete quantiles:
     discrete_quantile<integer_round_nearest>
  > my_policy;
  BOOST_MATH_DECLARE_DISTRIBUTIONS(double, my_policy)
} // close namespace my_namespace
int main()
{
   // Construct distribution with something we know will overflow.
   normal norm(10, 2); // using 'anonymous-namespace'::normal
   errno = 0;
   cout << "Result of quantile(norm, 0) is: "
      << quantile(norm, 0) << endl;
   cout << "errno = " << errno << endl;
   errno = 0;
   cout << "Result of quantile(norm, 1) is: "
      << quantile(norm, 1) << endl;
   cout << "errno = " << errno << endl;
   //
   // Now try a discrete distribution:
   binomial binom(20, 0.25);
   cout << "Result of quantile(binom, 0.05) is: "
      << quantile(binom, 0.05) << endl;
   cout << "Result of quantile(complement(binom, 0.05)) is: "
      << quantile(complement(binom, 0.05)) << endl;
}

PrevUpHomeNext

Статья Setting Policies at Namespace or Translation Unit Scope раздела Math Toolkit 2.5.0 Policy Tutorial может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Policy Tutorial ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 06:09:02/0.0075769424438477/0