diff options
author | Robert Clarke <clarke.john.robert@gmail.com> | 2023-02-14 16:57:09 +0100 |
---|---|---|
committer | Robert Clarke <clarke.john.robert@gmail.com> | 2023-02-14 16:57:09 +0100 |
commit | 436b9bd4d3372bdd96fd4f395f162c8b2f88023a (patch) | |
tree | 0c4d8789ab0d674fa48a462a564536fb2a9fa5d9 /docs/styleguide-cpp.md | |
parent | 39e3bd195b16402a85452415c32460d7cac1e26a (diff) |
Update of C++ styleguide
Diffstat (limited to 'docs/styleguide-cpp.md')
-rw-r--r-- | docs/styleguide-cpp.md | 338 |
1 files changed, 300 insertions, 38 deletions
diff --git a/docs/styleguide-cpp.md b/docs/styleguide-cpp.md index ad1add6..69471f5 100644 --- a/docs/styleguide-cpp.md +++ b/docs/styleguide-cpp.md @@ -1,58 +1,320 @@ # OpenVic2 C++ Style Guidelines ## Table of Contents - 1. [Why Style?](styleguide-cpp.md#why-style) + 1. [Why Style?](styleguide-cpp.md#1-why-style) - 1.1. [General Principles](styleguide-cpp.md#general-principles) + 1.1. [General Principles](styleguide-cpp.md#11-general-principles) - 1.2 [File Formatting](styleguide-cpp.md#file-formatting) + 1.2 [File Formatting](styleguide-cpp.md#12-file-formatting) - 2. [Conventions](styleguide-cpp.md#conventions) + 2. [Conventions](styleguide-cpp.md#2-conventions) - 2.1. [Naming Conventions](styleguide-cpp.md#-naming-conventions) + 2.1. [Naming Conventions](styleguide-cpp.md#21-naming-conventions) + + 2.2 [Do's and Don'ts](styleguide-cpp.md#22-dos-and-donts) ## 1. Why Style? -You may be wondering ”Why do we need a style guide?” ”Are you trying to give me homework?” -### 1.1. General Principles +>“Programs are meant to be read by humans and only incidentally for computers to execute.” +> - H. Abelson and G. Sussman in [*Structure and Interpretation of Computer Programs*](https://en.wikipedia.org/wiki/Structure_and_Interpretation_of_Computer_Programs) - - Prefer clarity over brevity - - Don’t optimize prematurely - - Avoid C-style casts +The purpose of this styleguide is to give a clear framework for other contributors, to minimize ambiguity, and to have a consistant way to convey the intent of code. + +### 1.1. General Principles +- Prefer clarity over brevity +- [Don’t optimize prematurely](https://youtu.be/tKbV6BpH-C8) +- In cases of ambiguity, use your best judgement ### 1.2. File Formatting Source code files should adhere to the following: - - Encoded in UTF-8 - - Use tabs for indentation - - Use LF for end-of-line sequences - - Not have any trailing whitespace (Lines which end in spaces or tabs - - Any #include directives should be at the top of the file +- Encoded in UTF-8 +- Use tabs for indentation +- Use LF for end-of-line sequences +- No trailing whitespace (Lines which end in spaces or tabs) +- Any `#include` directives should be at the top of the file +- Any header files have the `.hpp` file extension +- Any implementation files have the `.cpp` file extension +- Code should be within the `OpenVic2` namespace (or a nested namespace) +- Any submodules or third-party utilities should be in the `OpenVic2/extension/deps` directory +- Groups of related source files should be kept in a sub-directory of `OpenVic2/extension/src` +- Any lines that are longer than 120 characters in length should be split across multiple lines ## 2. Conventions ### 2.1 Naming Conventions | Item | Writing Convention | Example | |--|--|--| -| Class and Struct Names | Pascal Case | MyCoolExample | -| Variables and Function Names | Camel Case | myCoolExample | -| Constants, Enum Values and Preprocessor | Macro Case | MY_COOL_EXAMPLE | -| Type aliases | Snake Case | my_cool_example_t | - -```c++ -# pragma once -# include < stdio .h> -# include < iostream > -// A comment -constexpr size_t UNIQUE_RGB_COLOURS = 256 * 256 * 256; - -struct RGBColour { - unsigned char r ; - unsigned char g ; - unsigned char b ; -}; - -bool isColourGreyscale ( RGBColour c ); - -class Something { +| Class names | Pascal Case | MyCoolExample | +| Struct names | Pascal Case | MyCoolExample | +| Variable and Attribute names | Camel Case | myCoolExample | +| Function and Method names | Camel Case | myCoolExample | +| Constants | Macro Case | MY_COOL_EXAMPLE | +| Macros | Macro Case | MY_COOL_EXAMPLE | +| Class or container type aliases | Pascal Case | MyCoolExample | +| Builtin or numeric type aliases | Camel Case ( `_t` suffix) | myCoolExample_t | +| Enum names | Pascal Case | MyCoolExample | +| Enum values | Pascal Case | MyCoolExample | + + +### 2.2 Do's and Don'ts +- Keep the opening scope brace on the same line + ```c++ + //Correct + if (condition) { + //Cool things here + } + + //Incorrect + if (condition) + { + //cool things here + } + ``` +- With arithmetic, relational, and logical operators keep spaces between variables and literals + ```c++ + //Correct + int myNumber = (someVariable + 10) % 3; + + //Incorrect + int myNumber=(someVariable+10)%3; + ``` +- Prefix and postfix operators should be immediately attached to the affected variable + ```c++ + //Correct + for (int x = 0; x < 10; x++) { + //Something cool + } + + //Incorrect + for (int x = 0; x < 10; x ++ ) { + //Something cool + } + ``` +- The content of classes should appear in the following order: + - Type Aliases + - Static (class-wide) atributes + - Attributes + - Constructors and Destructors + - Static (class-wide) methods + - Methods + + ```c++ + class Human { + public: + using name_t = std::string; + + private: + static size_t numberOfHumans; + + public: + name_t name; + size_t age; + size_t familyMembers; + + Human(); + ~Human(); + + static bool isMoreHumansThan(size_t number); + + + private: + void coolPrivateMethod(); + + public: + void coolPublicMethod(); + void anotherCoolPublicMethod(); + + inline bool isVotingAge() const { + return age >= 18; + } + }; + ``` +- Class visibility specifiers should be followed by the next declaration on a new line at the same indentation level + - Group methods and attributes by their visibility specifier from most to least restrictive (`private`, `protected`, then `public`) + ```c++ + class ExampleClass { + //Attributes... + + private: + void firstPrivateMethod(); + void secondPrivateMethod(); + void thirdPrivateMethod(); + + protected: + void firstProtectedMethod(); + void secondProtectedMethod(); + void thirdProtectedMethod(); + + public: + void firstPublicMethod(); + void secondPublicMethod(); + void thirdPublicMethod(); + }; + ``` +- Methods which do not mutate an object's state should be marked as a `const` method + ```c++ + //Correct + bool RGBColour::isColourBlack() const { + return redChannel == 0 && greenChannel == 0 && blueChannel == 0; + } + + //Incorrect + bool RGBColour::isColourBlack() { + return redChannel == 0 && greenChannel == 0 && blueChannel == 0; + } + ``` +- When argument or parameter lists are too long to easily fit on one line: begin the argument list on the next line, two indentation levels higher than the function's indentation. + ```c++ + //Correct + callingAFunctionWithAVeryLongNameAndManyArguments( + longArgumentNameOne, longArgumentNameTwo, longArgumentNameThree, + longArgumentNameFour, longArgumentNameFive, longArgumentNameSix, + longArgumentNameSeven, longArgumentNameEight); -}; -```
\ No newline at end of file + //Incorrect + callingAFunctionWithAVeryLongNameAndManyArguments(longArgumentNameOne, longArgumentNameTwo, longArgumentNameThree, longArgumentNameFour, longArgumentNameFive, longArgumentNameSix, longArgumentNameSeven, longArgumentNameEight); + ``` +- In header files, put `#pragma once` at the top of the file, not C-style header guards + ```c++ + //Correct + #pragma once + /* + header contents here + */ + + //Incorrect + #ifndef MY_COOL_HEADER_H + #define MY_COOL_HEADER_H + /* + header contents here + */ + #endif + ``` +- Use enum classes, not plain enums + ```c++ + //Correct + enum class Colours { Red, Green, Blue, CharcoalGrey }; + + //Incorrect + enum Colours { Red, Green, Blue, CharcoalGrey }; + ``` +- Use type aliases, not `typedef`s + ```c++ + //Correct + using MyContainer = std::vector<int>; + using byte_t = unsigned char; + + //Incorrect + typedef std::vector<int> MyContainer; + typedef unsigned char byte_t; + ``` +- Use explicit types, do not use `auto` + ```c++ + //Correct + std::pair<int, int> coordinate = getPlayerLocation(); + + //Incorrect + auto coordinate = getPlayerLocation(); + ``` +- Do not use C-style casts, instead use C++ casts (ie: `static_cast`, `const_cast`, `reinterpret_cast`) + - `dynamic_cast` should only be used with caution + ```c++ + //Correct + int myNumber = static_cast<int>(someFloatValue); + + //Incorrect + int myNumber = (int) someFloatValue; + ``` +- When declaring a pointer, put the asterisk immediately after the type, followed by a space and the variable name + ```c++ + //Correct + int* myPointer = &myNumber; + + //Incorrect + int * myPointer = &myNumber; + int *myPointer = &myNumber; + int*myPointer = &myNumber; + ``` +- Do not declare multiple pointer variables on a single line + ```c++ + //Correct + int* p1; + int* p2; + + //Incorrect + int *p1, *p2; + ``` +- Keep the initialization of a variable and its declaration as close as possible, ideally on the same line. + ```c++ + //Correct + int myNumber = 23; + + //Incorrect + int myNumber; + myNumber = 23; + ``` +- For constant values that are computable at compile-time, use `constexpr` instead of the `const` keyword + ```c++ + //Correct + constexpr size_t UNIQUE_RGB_COLOURS = 256 * 256 * 256; + + //Incorrect + const size_t UNIQUE_RGB_COLOURS = 256 * 256 * 256; + ``` +- The name of functions returning a boolean value should start with `is` or `has`; whichever makes the most sense. + ```c++ + //Correct + bool isEven(int num) { + return num % 2 == 0; + } + + //Incorrect + bool even(int num) { + return num % 2 == 0; + } + ``` +- When a function parameter is being passed by const referance, put one space between the type and `const&`. If a parameter is passed by mutable reference do not put a space between the type and the `&` + ```c++ + //Correct for a const reference + bool hasLargeNumber(std::vector<int> const& numbers) { + //some cool stuff + return true; + } + + //Incorrect for a const reference + bool hasLargeNumber(std::vector<int>const& numbers) { + //some cool stuff + return true; + } + + //Correct for a mutable reference + bool hasLargeNumber(std::vector<int>& numbers) { + //some cool stuff + return true; + } + + //Incorrect for a mutable reference + bool hasLargeNumber(std::vector<int> & numbers) { + //some cool stuff + return true; + } + ``` +- The include order should be: C++ standard headers, followed by Godot headers, then OpenVic2 headers + - C++ standard headers and Godot headers should be enclosed by angle brackets `<>` + - OpenVic2 headers should be enclosed by double quotes `""` + ```c++ + //Correct + #include <vector> + #include <string> + #include <godot_cpp/classes/object.hpp> + #include <godot_cpp/core/class_db.hpp> + #include "openvic2/src/SampleHeader.hpp" + #include "openvic2/src/SampleHeader2.hpp" + + //Incorrect + #include "openvic2/src/SampleHeader.hpp" + #include <godot_cpp/classes/object.hpp> + #include "openvic2/src/SampleHeader2.hpp" + #include <godot_cpp/core/class_db.hpp> + #include <vector> + #include <string> + ``` |