Mercurial > malikania
annotate STYLE_CPP.md @ 142:473e1eb96363
Client: add simple splashscreen_state, #712
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 28 Sep 2017 12:36:15 +0200 |
parents | 835c8ee3f9e5 |
children |
rev | line source |
---|---|
118 | 1 Malikania Engine C++ CODING STYLE |
2 ================================= | |
3 | |
4 Style | |
5 ----- | |
6 | |
7 - Always use 4 spaces as indentation, | |
8 - Use UTF-8 charset, | |
9 - Use Unix line endings, | |
10 - Do not exceed 120 characters for lines of code, | |
11 - Do not exceed 80 characters for comments, | |
12 - Never write two blank consecutives blank lines, | |
13 - Do not use bad words. | |
14 | |
15 ### Braces | |
16 | |
17 Braces follow the K&R style, they are never placed on their own lines except for | |
18 function definitions. | |
19 | |
20 Do not put braces for single line statements except for clarity. | |
21 | |
22 if (condition) { | |
23 apply(); | |
24 add(); | |
25 } else | |
26 ok(); | |
27 | |
28 if (condition) | |
29 validate(); | |
30 | |
31 if (foo) { | |
32 state = long + conditional + that + requires + several + lines + | |
33 to + complete; | |
34 } | |
35 | |
36 Functions require braces on their own lines. | |
37 | |
38 void function() | |
39 { | |
40 } | |
41 | |
42 And a lambda has its braces on the same lines too: | |
43 | |
44 sort([&] (auto&) { | |
45 return true; | |
46 }); | |
47 | |
48 ### Spaces | |
49 | |
50 Each reserved keyword (e.g. `if`, `for`, `while`) requires a single space before | |
51 its argument. | |
52 | |
53 Normal function calls do not require it. | |
54 | |
55 if (foo) | |
56 destroy(sizeof (int)); | |
57 | |
58 ### References and pointers | |
59 | |
60 References and pointers are always next to the type name and not the variable. | |
61 | |
62 T& get(const std::string& name); | |
63 | |
64 int* p = &x; | |
65 | |
66 ### Naming | |
67 | |
68 - English names, | |
69 - Member variables have trailing underscore (e.g foo\_bar\_), | |
70 - No hungarian notation. | |
71 | |
72 Everything is in `underscore_case` except template parameters and macros. | |
73 | |
74 #if defined(FOO) | |
75 # include <foo.hpp> | |
76 #endif | |
77 | |
78 namespace baz { | |
79 | |
80 class object { | |
81 private: | |
82 std::string name_; | |
83 | |
84 public: | |
85 inline const std::string& name() const noexcept | |
86 { | |
87 return name_; | |
88 } | |
89 }; | |
90 | |
91 template <typename Archive> | |
92 void open(const Archive& ar) | |
93 { | |
94 bool is_valid = false; | |
95 } | |
96 | |
97 } // !baz | |
98 | |
99 ### Header guards | |
100 | |
101 Do not use `#pragma once`. | |
102 | |
103 Header guards are usually named **PROJECT_COMPONENT_FILENAME_HPP**. | |
104 | |
105 #ifndef FOO_COMMON_UTIL_HPP | |
106 #define FOO_COMMON_UTIL_HPP | |
107 | |
108 #endif // !FOO_COMMON_UTIL_HPP | |
109 | |
110 ### Enums | |
111 | |
112 Enumerations constants are always defined in separate line to allow commenting | |
113 them as doxygen. | |
114 | |
115 Enum class are encouraged. | |
116 | |
117 enum class color { | |
118 blue, | |
119 red, | |
120 green | |
121 }; | |
122 | |
123 ### Files | |
124 | |
125 - Use `.cpp` and `.hpp` as file extensions, | |
126 - Filenames are all lowercase. | |
127 | |
128 ### Comments | |
129 | |
130 Avoid useless comments in source files. Comment complex things or why it is done | |
131 like this. However any public function in the .hpp **must** be documented as | |
132 doxygen without exception. | |
133 | |
134 /* | |
135 * Multi line comments look like | |
136 * this. | |
137 */ | |
138 | |
139 // Short comment | |
140 | |
141 Use `#if 0` to comment blocks of code. | |
142 | |
143 #if 0 | |
144 broken_stuff(); | |
145 #endif | |
146 | |
147 ### Includes | |
148 | |
149 The includes should always come in the following order. | |
150 | |
151 1. C++ headers | |
152 2. C header | |
153 3. Third party libraries | |
154 4. Application headers in "" | |
155 | |
156 #include <cstring> | |
157 #include <cerrno> | |
158 | |
159 #include <sys/stat.h> | |
160 | |
161 #include <libircclient.h> | |
162 | |
163 #include "foo.h" | |
164 | |
165 **Note**: always use C++ headers for C equivalent, stdio.h -> cstdio, etc. | |
166 | |
167 ### Commit messages | |
168 | |
169 Commit messages are written using the following syntax: | |
170 | |
171 Topic: short message less than 80 characters | |
172 | |
173 Optional additional description if needed. | |
174 | |
175 Replace `Topic` with one of the following: | |
176 | |
177 - **Client**: client library and executable, | |
178 - **CMake**: for the build system, | |
179 - **Common**: common library, | |
180 - **Docs**: for the documentation, | |
181 - **Misc**: for miscellaneous files, | |
182 - **Server**: server library and executable, | |
183 - **Tests**: for the unit tests. | |
184 | |
185 Programming | |
186 ----------- | |
187 | |
188 ### C language | |
189 | |
190 Do not use old C stuff like `void *`, `srand/rand`, `printf` or anything that | |
191 can be rewritten in modern C++. | |
192 | |
193 ### RTTI | |
194 | |
195 Usage of `dynamic_cast` and `typeid` are completely disallowed in any shape of | |
196 form. | |
197 | |
198 ### Arguments | |
199 | |
200 It is recommended to pass parameters by value or const reference. Usage of | |
201 non-const reference as output parameter is **discouraged** and should be avoided | |
202 in many case because it does not allow chaining of expressions like: | |
203 | |
204 std::cout << reverse(upper(clean(" hello world! "))) << std::endl; | |
205 | |
206 If your function is designed to return a modified value passed as argument, it | |
207 is better to take it by value and modify it directly. | |
208 | |
209 std::string clean(std::string input) | |
210 { | |
211 if (!input.empty() && input.back() == '\r') | |
212 input.pop_back(); | |
213 | |
214 return input; | |
215 } | |
216 | |
217 Never pass primitive types as const value. | |
218 | |
219 ### Assertions | |
220 | |
221 Use the `assert` macro from the cassert header file to verify programming | |
222 errors. | |
223 | |
224 For example, you may use `assert` to verify that the developer access the data | |
225 between the bounds of an array: | |
226 | |
227 T& operator[](unsigned index) | |
228 { | |
229 assert(index < length_); | |
230 | |
231 return data_[index]; | |
232 } | |
233 | |
234 The `assert` macro is not meant to check that a function succeeded, this code | |
235 must not be written that way: | |
236 | |
237 assert(listen(10)); | |
238 | |
239 ### Exceptions | |
240 | |
241 You must use exceptions to indicate an error that was unexpected such as: | |
242 | |
243 - Failing to open a file, | |
244 - I/O unexpected errors, | |
245 - Parsing errors, | |
246 - User errors. | |
247 | |
248 You may use the C++ standard exceptions defined in the stdexcept header but if | |
249 you need to carry more data within your exception, you should derive from | |
250 `std::exception`. | |
251 | |
252 ### Error code | |
253 | |
254 You should not use error codes to indicate errors, instead use exceptions. | |
255 Error codes are allowed in Boost.Asio though. | |
256 | |
257 ### Free functions | |
258 | |
259 Basic utility functions should be defined in a namespace as a free function not | |
260 as a static member function, we're doing C++ not Java. | |
261 | |
262 Example: | |
263 | |
264 namespace util { | |
265 | |
266 std::string clean(std::string input); | |
267 | |
268 } // !util | |
269 | |
270 ### Variables initialization | |
271 | |
272 Use parentheses to initialize non primitive types: | |
273 | |
274 throw std::runtime_error("foo"); | |
275 | |
276 my_class obj("bar"); | |
277 | |
278 Use brace initialization when you want to use an initializer list, type | |
279 elision: | |
280 | |
281 std::vector<int> v{1, 2, 3}; | |
282 | |
283 foo({1, 2}); // type deduced | |
284 | |
285 return { "true", false }; // std::pair returned | |
286 | |
287 Use the assignment for primitive types: | |
288 | |
289 int x = 123; | |
290 bool is_valid = true; | |
291 | |
292 ### Classes | |
293 | |
294 Classes are usually defined in the following order: | |
295 | |
296 1. Public inner types (enums, classes), | |
297 2. Protected/private members | |
298 3. Public functions | |
299 | |
300 class foo { | |
301 public: | |
302 enum class type { | |
303 a, | |
304 b | |
305 }; | |
306 | |
307 private: | |
308 int member_{0}; | |
309 | |
310 public: | |
311 void some_function(); | |
312 }; | |
313 | |
314 ### Structs | |
315 | |
316 Do not use C structs unless you have very good reason to do so. If you want to | |
317 pack some data, just use `class` and make all fields public. | |
318 | |
319 class point { | |
320 public: | |
321 int x{0}; | |
322 int y{0}; | |
323 }; | |
324 | |
325 ### Return | |
326 | |
327 The preferred style is to return early in case of errors. That makes the code | |
328 more linear and not highly indented. | |
329 | |
330 This code is preferred: | |
331 | |
332 if (a_condition_is_not_valid) | |
333 return nullptr; | |
334 if (an_other_condition) | |
335 return nullptr; | |
336 | |
337 auto x = std::make_shared<object>(); | |
338 | |
339 x->start(); | |
340 x->save(); | |
341 | |
342 return x; | |
343 | |
344 Additional rules: | |
345 | |
346 - Do never put parentheses between the returned value, | |
347 - Do not put a else branch after a return. | |
348 | |
349 ### Auto | |
350 | |
351 We encorage usage of `auto`, it reduces code maintainance as you don't need to | |
352 change your code when your rename types. | |
353 | |
136
835c8ee3f9e5
Docs: use ``` as fenced code blocks
David Demelier <markand@malikania.fr>
parents:
118
diff
changeset
|
354 ```cpp |
118 | 355 auto it = std::find_if(v.begin(), v.end(), [&] (const auto& obj) { |
356 return obj.key() == "foo"; | |
357 }); | |
358 | |
359 for (const auto& pair : a_map) | |
360 std::cout << pair.first << " = " << pair.second << std::endl; | |
136
835c8ee3f9e5
Docs: use ``` as fenced code blocks
David Demelier <markand@malikania.fr>
parents:
118
diff
changeset
|
361 ``` |
118 | 362 |
363 But do not use `auto` to write code like in python, this is not acceptable: | |
364 | |
136
835c8ee3f9e5
Docs: use ``` as fenced code blocks
David Demelier <markand@malikania.fr>
parents:
118
diff
changeset
|
365 ```cpp |
118 | 366 auto o = my_object("foo"); |
136
835c8ee3f9e5
Docs: use ``` as fenced code blocks
David Demelier <markand@malikania.fr>
parents:
118
diff
changeset
|
367 ``` |