# HG changeset patch # User David Demelier # Date 1508331796 -7200 # Node ID 314e8bb2659ada0373807b7b456ed9580029b6b4 # Parent 780c138ab41dbf9c898a548eba4337f864695f6d Rename STYLE_CPP.md to STYLE.md diff -r 780c138ab41d -r 314e8bb2659a STYLE.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/STYLE.md Wed Oct 18 15:03:16 2017 +0200 @@ -0,0 +1,380 @@ +PROJECT NAME CODING STYLE +========================= + +C++ +=== + +Style +----- + + - Always use 4 spaces as indentation, + - Use UTF-8 charset, + - Use Unix line endings, + - Do not exceed 120 characters for lines of code, + - Do not exceed 80 characters for comments, + - Never write two blank consecutives blank lines, + - Do not use bad words. + +### Braces + +Braces follow the K&R style, they are never placed on their own lines except for +function definitions. + +Do not put braces for single line statements except for clarity. + + if (condition) { + apply(); + add(); + } else + ok(); + + if (condition) + validate(); + + if (foo) { + state = long + conditional + that + requires + several + lines + + to + complete; + } + +Functions require braces on their own lines. + + void function() + { + } + +And a lambda has its braces on the same lines too: + + sort([&] (auto&) { + return true; + }); + +### Spaces + +Each reserved keyword (e.g. `if`, `for`, `while`) requires a single space before +its argument. + +Normal function calls do not require it. + + if (foo) + destroy(sizeof (int)); + +### References and pointers + +References and pointers are always next to the type name and not the variable. + + T& get(const std::string& name); + + int* p = &x; + +### Naming + + - English names, + - Member variables have trailing underscore (e.g foo\_bar\_), + - No hungarian notation. + +Everything is in `underscore_case` except template parameters and macros. + + #if defined(FOO) + # include + #endif + + namespace baz { + + class object { + private: + std::string name_; + + public: + inline const std::string& name() const noexcept + { + return name_; + } + }; + + template + void open(const Archive& ar) + { + bool is_valid = false; + } + + } // !baz + +### Header guards + +Do not use `#pragma once`. + +Header guards are usually named **PROJECT_COMPONENT_FILENAME_HPP**. + + #ifndef FOO_COMMON_UTIL_HPP + #define FOO_COMMON_UTIL_HPP + + #endif // !FOO_COMMON_UTIL_HPP + +### Enums + +Enumerations constants are always defined in separate line to allow commenting +them as doxygen. + +Enum class are encouraged. + + enum class color { + blue, + red, + green + }; + +### Switch + +In a switch case statement, you **must** not declare variables and not indent +cases. + + switch (variable) { + case foo: + do_some_stuff(); + break; + default: + break; + } + +### Files + + - Use `.cpp` and `.hpp` as file extensions, + - Filenames are all lowercase. + +### Comments + +Avoid useless comments in source files. Comment complex things or why it is done +like this. However any public function in the .hpp **must** be documented as +doxygen without exception. + + /* + * Multi line comments look like + * this. + */ + + // Short comment + +Use `#if 0` to comment blocks of code. + +#if 0 + broken_stuff(); +#endif + +### Includes + +The includes should always come in the following order. + + 1. C++ headers + 2. C header + 3. Third party libraries + 4. Application headers in "" + + #include + #include + + #include + + #include + + #include "foo.h" + +**Note**: always use C++ headers for C equivalent, stdio.h -> cstdio, etc. + +### Commit messages + +Commit messages are written using the following syntax: + + Topic: short message less than 80 characters + + Optional additional description if needed. + +Replace `Topic` with one of the following: + + - **CMake**: for the build system, + - **Docs**: for the documentation, + - **Misc**: for miscellaneous files, + - **Tests**: for the unit tests. + +Programming +----------- + +### C language + +Do not use old C stuff like `void *`, `srand/rand`, `printf` or anything that +can be rewritten in modern C++. + +### RTTI + +Usage of `dynamic_cast` and `typeid` are completely disallowed in any shape of +form. + +### Arguments + +It is recommended to pass parameters by value or const reference. Usage of +non-const reference as output parameter is **discouraged** and should be avoided +in many case because it does not allow chaining of expressions like: + + std::cout << reverse(upper(clean(" hello world! "))) << std::endl; + +If your function is designed to return a modified value passed as argument, it +is better to take it by value and modify it directly. + + std::string clean(std::string input) + { + if (!input.empty() && input.back() == '\r') + input.pop_back(); + + return input; + } + +Never pass primitive types as const value. + +### Assertions + +Use the `assert` macro from the cassert header file to verify programming +errors. + +For example, you may use `assert` to verify that the developer access the data +between the bounds of an array: + + T& operator[](unsigned index) + { + assert(index < length_); + + return data_[index]; + } + +The `assert` macro is not meant to check that a function succeeded, this code +must not be written that way: + + assert(listen(10)); + +### Exceptions + +You must use exceptions to indicate an error that was unexpected such as: + + - Failing to open a file, + - I/O unexpected errors, + - Parsing errors, + - User errors. + +You may use the C++ standard exceptions defined in the stdexcept header but if +you need to carry more data within your exception, you should derive from +`std::exception`. + +### Error code + +You should not use error codes to indicate errors, instead use exceptions. +Error codes are allowed in Boost.Asio though. + +### Free functions + +Basic utility functions should be defined in a namespace as a free function not +as a static member function, we're doing C++ not Java. + +Example: + + namespace util { + + std::string clean(std::string input); + + } // !util + +### Variables initialization + +Use parentheses to initialize non primitive types: + + throw std::runtime_error("foo"); + + my_class obj("bar"); + +Use brace initialization when you want to use an initializer list, type +elision: + + std::vector v{1, 2, 3}; + + foo({1, 2}); // type deduced + + return { "true", false }; // std::pair returned + +Use the assignment for primitive types: + + int x = 123; + bool is_valid = true; + +### Classes + +Classes are usually defined in the following order: + + 1. Public inner types (enums, classes), + 2. Protected/private members + 3. Public functions + + class foo { + public: + enum class type { + a, + b + }; + + private: + int member_{0}; + + public: + void some_function(); + }; + +### Structs + +Do not use C structs unless you have very good reason to do so. If you want to +pack some data, just use `class` and make all fields public. + + class point { + public: + int x{0}; + int y{0}; + }; + +### Return + +The preferred style is to return early in case of errors. That makes the code +more linear and not highly indented. + +This code is preferred: + + if (a_condition_is_not_valid) + return nullptr; + if (an_other_condition) + return nullptr; + + auto x = std::make_shared(); + + x->start(); + x->save(); + + return x; + +Additional rules: + + - Do never put parentheses between the returned value, + - Do not put a else branch after a return. + +### Auto + +We encorage usage of `auto`, it reduces code maintainance as you don't need to +change your code when your rename types. + +````cpp +auto it = std::find_if(v.begin(), v.end(), [&] (const auto& obj) { + return obj.key() == "foo"; +}); + +for (const auto& pair : a_map) + std::cout << pair.first << " = " << pair.second << std::endl; +```` + +But do not use `auto` to write code like in python, this is not acceptable: + +````cpp + auto o = my_object("foo"); +```` diff -r 780c138ab41d -r 314e8bb2659a STYLE_CPP.md --- a/STYLE_CPP.md Wed Oct 04 10:13:39 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,377 +0,0 @@ -PROJECT NAME C++ CODING STYLE -============================= - -Style ------ - - - Always use 4 spaces as indentation, - - Use UTF-8 charset, - - Use Unix line endings, - - Do not exceed 120 characters for lines of code, - - Do not exceed 80 characters for comments, - - Never write two blank consecutives blank lines, - - Do not use bad words. - -### Braces - -Braces follow the K&R style, they are never placed on their own lines except for -function definitions. - -Do not put braces for single line statements except for clarity. - - if (condition) { - apply(); - add(); - } else - ok(); - - if (condition) - validate(); - - if (foo) { - state = long + conditional + that + requires + several + lines + - to + complete; - } - -Functions require braces on their own lines. - - void function() - { - } - -And a lambda has its braces on the same lines too: - - sort([&] (auto&) { - return true; - }); - -### Spaces - -Each reserved keyword (e.g. `if`, `for`, `while`) requires a single space before -its argument. - -Normal function calls do not require it. - - if (foo) - destroy(sizeof (int)); - -### References and pointers - -References and pointers are always next to the type name and not the variable. - - T& get(const std::string& name); - - int* p = &x; - -### Naming - - - English names, - - Member variables have trailing underscore (e.g foo\_bar\_), - - No hungarian notation. - -Everything is in `underscore_case` except template parameters and macros. - - #if defined(FOO) - # include - #endif - - namespace baz { - - class object { - private: - std::string name_; - - public: - inline const std::string& name() const noexcept - { - return name_; - } - }; - - template - void open(const Archive& ar) - { - bool is_valid = false; - } - - } // !baz - -### Header guards - -Do not use `#pragma once`. - -Header guards are usually named **PROJECT_COMPONENT_FILENAME_HPP**. - - #ifndef FOO_COMMON_UTIL_HPP - #define FOO_COMMON_UTIL_HPP - - #endif // !FOO_COMMON_UTIL_HPP - -### Enums - -Enumerations constants are always defined in separate line to allow commenting -them as doxygen. - -Enum class are encouraged. - - enum class color { - blue, - red, - green - }; - -### Switch - -In a switch case statement, you **must** not declare variables and not indent -cases. - - switch (variable) { - case foo: - do_some_stuff(); - break; - default: - break; - } - -### Files - - - Use `.cpp` and `.hpp` as file extensions, - - Filenames are all lowercase. - -### Comments - -Avoid useless comments in source files. Comment complex things or why it is done -like this. However any public function in the .hpp **must** be documented as -doxygen without exception. - - /* - * Multi line comments look like - * this. - */ - - // Short comment - -Use `#if 0` to comment blocks of code. - -#if 0 - broken_stuff(); -#endif - -### Includes - -The includes should always come in the following order. - - 1. C++ headers - 2. C header - 3. Third party libraries - 4. Application headers in "" - - #include - #include - - #include - - #include - - #include "foo.h" - -**Note**: always use C++ headers for C equivalent, stdio.h -> cstdio, etc. - -### Commit messages - -Commit messages are written using the following syntax: - - Topic: short message less than 80 characters - - Optional additional description if needed. - -Replace `Topic` with one of the following: - - - **CMake**: for the build system, - - **Docs**: for the documentation, - - **Misc**: for miscellaneous files, - - **Tests**: for the unit tests. - -Programming ------------ - -### C language - -Do not use old C stuff like `void *`, `srand/rand`, `printf` or anything that -can be rewritten in modern C++. - -### RTTI - -Usage of `dynamic_cast` and `typeid` are completely disallowed in any shape of -form. - -### Arguments - -It is recommended to pass parameters by value or const reference. Usage of -non-const reference as output parameter is **discouraged** and should be avoided -in many case because it does not allow chaining of expressions like: - - std::cout << reverse(upper(clean(" hello world! "))) << std::endl; - -If your function is designed to return a modified value passed as argument, it -is better to take it by value and modify it directly. - - std::string clean(std::string input) - { - if (!input.empty() && input.back() == '\r') - input.pop_back(); - - return input; - } - -Never pass primitive types as const value. - -### Assertions - -Use the `assert` macro from the cassert header file to verify programming -errors. - -For example, you may use `assert` to verify that the developer access the data -between the bounds of an array: - - T& operator[](unsigned index) - { - assert(index < length_); - - return data_[index]; - } - -The `assert` macro is not meant to check that a function succeeded, this code -must not be written that way: - - assert(listen(10)); - -### Exceptions - -You must use exceptions to indicate an error that was unexpected such as: - - - Failing to open a file, - - I/O unexpected errors, - - Parsing errors, - - User errors. - -You may use the C++ standard exceptions defined in the stdexcept header but if -you need to carry more data within your exception, you should derive from -`std::exception`. - -### Error code - -You should not use error codes to indicate errors, instead use exceptions. -Error codes are allowed in Boost.Asio though. - -### Free functions - -Basic utility functions should be defined in a namespace as a free function not -as a static member function, we're doing C++ not Java. - -Example: - - namespace util { - - std::string clean(std::string input); - - } // !util - -### Variables initialization - -Use parentheses to initialize non primitive types: - - throw std::runtime_error("foo"); - - my_class obj("bar"); - -Use brace initialization when you want to use an initializer list, type -elision: - - std::vector v{1, 2, 3}; - - foo({1, 2}); // type deduced - - return { "true", false }; // std::pair returned - -Use the assignment for primitive types: - - int x = 123; - bool is_valid = true; - -### Classes - -Classes are usually defined in the following order: - - 1. Public inner types (enums, classes), - 2. Protected/private members - 3. Public functions - - class foo { - public: - enum class type { - a, - b - }; - - private: - int member_{0}; - - public: - void some_function(); - }; - -### Structs - -Do not use C structs unless you have very good reason to do so. If you want to -pack some data, just use `class` and make all fields public. - - class point { - public: - int x{0}; - int y{0}; - }; - -### Return - -The preferred style is to return early in case of errors. That makes the code -more linear and not highly indented. - -This code is preferred: - - if (a_condition_is_not_valid) - return nullptr; - if (an_other_condition) - return nullptr; - - auto x = std::make_shared(); - - x->start(); - x->save(); - - return x; - -Additional rules: - - - Do never put parentheses between the returned value, - - Do not put a else branch after a return. - -### Auto - -We encorage usage of `auto`, it reduces code maintainance as you don't need to -change your code when your rename types. - -````cpp -auto it = std::find_if(v.begin(), v.end(), [&] (const auto& obj) { - return obj.key() == "foo"; -}); - -for (const auto& pair : a_map) - std::cout << pair.first << " = " << pair.second << std::endl; -```` - -But do not use `auto` to write code like in python, this is not acceptable: - -````cpp - auto o = my_object("foo"); -````