Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Use in template code

When using the constants inside a function template, we need to ensure that we use a constant of the correct precision for our template parameters. We can do this by calling the function-template versions, pi<FPType>(), of the constants like this:

#include <boost/math/constants/constants.hpp>

template <class Real>
Real area(Real r)
{
   using namespace boost::math::constants;
   return pi<Real>() * r * r;
}

Although this syntax is a little less "cute" than the non-template version, the code is no less efficient (at least for the built-in types float, double and long double) : the function template versions of the constants are simple inline functions that return a constant of the correct precision for the type used. In addition, these functions are declared constexp for those compilers that support this, allowing the result to be used in constant-expressions provided the template argument is a literal type.

[Tip] Tip

Keep in mind the difference between the variable version, just pi, and the template-function version: the template-function requires both a <floating-point-type> and function call () brackets, for example: pi<double>(). You cannot write double p = pi<>(), nor double p = pi().

[Note] Note

You can always use both variable and template-function versions provided calls are fully qualified, for example:

double my_pi1 = boost::math::constants::pi<double>();
double my_pi2 = boost::math::double_constants::pi;
[Warning] Warning

It may be tempting to simply define

using namespace boost::math::double_constants;
using namespace boost::math::constants;

but if you do define two namespaces, this will, of course, create ambiguity!

double my_pi = pi(); // error C2872: 'pi' : ambiguous symbol
double my_pi2 = pi; // Context does not allow for disambiguation of overloaded function

Although the mistake above is fairly obvious, it is also not too difficult to do this accidentally, or worse, create it in someone elses code.

Therefore is it prudent to avoid this risk by localising the scope of such definitions, as shown above.

[Tip] Tip

Be very careful with the type provided as parameter. For example, providing an integer instead of a floating-point type can be disastrous (a C++ feature).

cout << "Area = " << area(2) << endl; // Area = 12!!!

You should get a compiler warning

warning : 'return' : conversion from 'double' to 'int', possible loss of data

Failure to heed this warning can lead to very wrong answers!

You can also avoid this by being explicit about the type of Area.

cout << "Area = " << area<double>(2) << endl; // Area = 12.566371

PrevUpHomeNext