Developer/Guidelines
This document outlines guidelines and policies that should be followed in the process of development of Boost.Geometry.
It is aimed to propose Boost.Geometry to the collection of Boost C++ Libraries, so it is intentional to closely follow Boost conventions. As such, this document is based on Boost Library Requirements and Guidelines and Boost Header Policy. In case of doubts in any subject, refer to Boost guidelines.
Headers include order
- C Standard Library (using C++ library names, i.e. <cstdlib>)
- C++ Standard Library (std namespace)
- Boost C++ Libraries (boost namespace)
- Boost.Geometry headers
- Other 3rd-party headers (only if applicable! in some samples only)
It's usually a good idea to keep headers ordered alphabetically within these sections, especially if there are many of headers.
Macros
All names of preprocessor macros are always UPPER-CASE and words/tokens are separated with underscore (_). Macro identifiers must not begin with one or more underscores, such names are reserved according to the C++ Language Standard. Generally, it's a good practice to avoid macros if you can and use them only when you have to.
Include guards
Names of include guards are constructed as follows:
BOOST_GEOMETRY_<DIRECTORY 1>_<DIRECTORY N>_<FILE>_HPP
For example, header boost/geometry/strategies/distance_result.hpp is guarded as follows.
#ifndef BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP #define BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP // ... #endif // BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP
It is not necessary to append _INCLUDED postfix
Formatting
- Use spaces in all source files. Strictly, no tabs.
- Prefered line length is 80 characters, however maximum is 100 characters in line.
- Do not indent namespace blocks.
- Prefer readable formatting and indentation of long template definition. Possible indentation layout is presented below:
template < typename T, typename P, typename C = std::vector<Point> > struct polygon { typedef typename boost::remove_const < typename traits::point_type<T>::type >::type type };
Naming convention
- Use m_ prefix for member variables as readable form. The Boost sample header gives no prefix/suffix at all. However, the m_ prefix is used in some (not many) boost libraries as well (e.g. math/tools/remez).
- Do not prefix or postfix any names with underscore.
Miscellaneous
- Keyword struct is preferred either for POD structures, or for classes used at compile-time like metafunctions, tags, traits, etc.
- Keyword class is preferred for classes meant to produce actual objects, which have methods and an active role in the runtime functioning of the program.
- In case of a template, prefer use of typename keyword over class.
- Order access specifiers for class members as public first, then protected and private at the bottom. The public members define class interface, thus they are of the highest interested for users, so show them first.
- Exceptions are possible for typedef aliases required to be defined first.
- For references to const object, the const qualifier is placed after the type and it's a good idea to follow this guideline for pointer to const object - it read it right to left:
Point const& point; void foo(Point const* point);
Example
Guidelines summary example:
namespace boost { namespace geometry { namespace a { template <typename T> struct sample1 { typedef T type; }; template <typename T> class sample2 { public: sample2(T a, T b) : m_a(a), m_b(b) {} void foo() {} protected: void bar() {} private: T m_a; T m_b; }; } // namespace a }} // namespace boost::geometry
Dispatching and specializations
- Algorithms are free inline functions, taking any geometry. Parameters are often one or two geometries
- There might be an overload for a strategy. The strategy takes, a.o. care of coordinate systems
- The free inline function forwards to a dispatch struct, specialized for the geometry type (so for point, polygon, etc)
- They have an static (inline) function called apply
- All template parameters are in the struct, so no member template functions there
- The dispatch struct calls, or is derived from, an struct implemented in namespace detail
- There the same: a struct with a static (inline) function called apply
- This way the implementation structs are building blocks, they can be reused
- In fact they are reused often by the multi-versions of the algorithms
Example
Example for simple structs
namespace boost { namespace geometry { namespace detail { namespace foo { template <typename Point> struct foo_point { // template parameters here static inline int apply(Point const& p) { // do something here return 1; } }; }} // namespace detail::foo namespace dispatch { template <Tag, Geometry> struct foo { }; // Specialization for POINT template <typename Point> struct foo<point_tag, Point> : detail::foo::foo_point<Point> {}; // Specialization for polygon template <typename Polygon> struct foo<polygon_tag, Polygon> : detail::foo::foo_polygon<Polygon> {}; } // namespace dispatch template <typename Point> inline int foo(Point const& point) { return dispatch<typename tag<Point>::type, Point>::apply(point); } }} // namespace boost::geometry
