All declarations and definitions must be in the ignite
namespace. It is allowed to have namespaces nested to the ignite
namespace. The technical implementation details that are not part of the public API should be in the nested detail
namespaces.
It is required to mark the namespace end with the comment indicating its name.
namespace ignite { namespace detail { // Implementation details, not to be used directly. } // namespace detail // Public interface. } // namespace ignite
Namespaces do not introduce additional indentation level.
We use 4 spaces for indentation inside structs, classes, functions, nested statements, and blocks of C++ code. TAB characters are not allowed.
namespace ignite::sample { int square(int x) { return x * x; } class counter { public: unsigned int inc() { unsignned int ret; { std::unique_lock lock(m_mutex); ret = m_value++; if (m_value == 0) throw std::runtime_error("counter overflow"); } log("counter incremented to " + std::to_string(ret + 1)); return ret; } private: unsigned int m_value = 0; std::mutex m_mutex; }; } // namespace ignite::sample
We use 1-space indentation after the #
char for nested preprocessor directives.
#ifdef HAS_FOO # include "foo.h" # ifdef HAS_BAR # include "bar.h" # endif #endif
We use lower case with undescore between words for almost everything:
For constants we use upper case with undescore between words. Macro constants must start with the IGNITE_
prefix.
For private/protected class fields it is allowed but not required to use the m_
prefix.
#ifndef IGNITE_FOO_LIMIT # define IGNITE_FOO_LIMIT 42 #endif namespace ignite::sample { class foo_tester { public: static constexpr unsigned int LIMIT = IGNITE_FOO_LIMIT; enum test_result { BELOW_LIMIT, AT_LIMIT, ABOVE_LIMIT, }; test_result test_limit() { int value = m_counter().inc(); return value < LIMIT ? BELOW_LIMIT : value == LIMIT ? AT_LIMIT : ABOVE_LIMIT; } private: counter m_counter; }; } // namespace ignite::sample
Template m_parameters are an exception from this rule.
template <typename T, typename IterT> void foo(T a, IterT b) { // ... }
Header files are included in order from more specific to less specific:
These groups are separated by an empty line. Inside each group files are sorted in alphabetical order.
In addition to consistency this include order has one techical advantage. It's good if each header #include
s all the headers it depends on itself. And this order allows to detect sooner if there is any missing dependency.