comparison STYLE.md @ 17:314e8bb2659a

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