Mercurial > template
annotate STYLE_CPP.md @ 13:4d6bf8b3446d
Add chapter about auto
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 08 Sep 2017 11:25:02 +0200 |
parents | ba9d0618d0ff |
children | 55bb3689093f |
rev | line source |
---|---|
0 | 1 PROJECT NAME C++ CODING STYLE |
2 ============================= | |
3 | |
4 Style | |
5 ----- | |
6 | |
7 - Always use 4 spaces as indentation, | |
9
ee0ef058cb94
Add note about UTF-8 / LF
David Demelier <markand@malikania.fr>
parents:
8
diff
changeset
|
8 - Use UTF-8 charset, |
ee0ef058cb94
Add note about UTF-8 / LF
David Demelier <markand@malikania.fr>
parents:
8
diff
changeset
|
9 - Use Unix line endings, |
0 | 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, | |
7
4fcd920b1a02
Add note about bad words
David Demelier <markand@malikania.fr>
parents:
6
diff
changeset
|
13 - Do not use bad words. |
0 | 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 | |
10 | 20 Do not put braces for single line statements except for clarity. |
0 | 21 |
22 if (condition) { | |
23 apply(); | |
24 add(); | |
10 | 25 } else |
0 | 26 ok(); |
10 | 27 |
28 if (condition) | |
29 validate(); | |
30 | |
31 if (foo) { | |
32 state = long + conditional + that + requires + several + lines + | |
33 to + complete; | |
0 | 34 } |
35 | |
10 | 36 Functions require braces on their own lines. |
37 | |
38 void function() | |
39 { | |
0 | 40 } |
41 | |
42 And a lambda has its braces on the same lines too: | |
43 | |
13
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
44 sort([&] (auto&) { |
0 | 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 | |
11 | 55 if (foo) |
0 | 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, | |
8
d7cbb9a40f0d
Member variables are now named like_this_
David Demelier <markand@malikania.fr>
parents:
7
diff
changeset
|
69 - Member variables have trailing underscore (e.g foo\_bar\_), |
0 | 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: | |
8
d7cbb9a40f0d
Member variables are now named like_this_
David Demelier <markand@malikania.fr>
parents:
7
diff
changeset
|
82 std::string name_; |
0 | 83 |
84 public: | |
85 inline const std::string& name() const noexcept | |
86 { | |
8
d7cbb9a40f0d
Member variables are now named like_this_
David Demelier <markand@malikania.fr>
parents:
7
diff
changeset
|
87 return name_; |
0 | 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 | |
2 | 141 Use `#if 0` to comment blocks of code. |
142 | |
143 #if 0 | |
144 broken_stuff(); | |
145 #endif | |
146 | |
0 | 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 - **CMake**: for the build system, | |
178 - **Docs**: for the documentation, | |
179 - **Misc**: for miscellaneous files, | |
3 | 180 - **Tests**: for the unit tests. |
0 | 181 |
182 Programming | |
183 ----------- | |
184 | |
185 ### C language | |
186 | |
187 Do not use old C stuff like `void *`, `srand/rand`, `printf` or anything that | |
188 can be rewritten in modern C++. | |
189 | |
190 ### RTTI | |
191 | |
192 Usage of `dynamic_cast` and `typeid` are completely disallowed in any shape of | |
193 form. | |
194 | |
195 ### Arguments | |
196 | |
197 It is recommended to pass parameters by value or const reference. Usage of | |
198 non-const reference as output parameter is **discouraged** and should be avoided | |
199 in many case because it does not allow chaining of expressions like: | |
200 | |
201 std::cout << reverse(upper(clean(" hello world! "))) << std::endl; | |
202 | |
203 If your function is designed to return a modified value passed as argument, it | |
204 is better to take it by value and modify it directly. | |
205 | |
206 std::string clean(std::string input) | |
207 { | |
11 | 208 if (!input.empty() && input.back() == '\r') |
0 | 209 input.pop_back(); |
210 | |
211 return input; | |
212 } | |
213 | |
214 Never pass primitive types as const value. | |
215 | |
216 ### Assertions | |
217 | |
218 Use the `assert` macro from the cassert header file to verify programming | |
219 errors. | |
220 | |
221 For example, you may use `assert` to verify that the developer access the data | |
222 between the bounds of an array: | |
223 | |
224 T& operator[](unsigned index) | |
225 { | |
8
d7cbb9a40f0d
Member variables are now named like_this_
David Demelier <markand@malikania.fr>
parents:
7
diff
changeset
|
226 assert(index < length_); |
0 | 227 |
8
d7cbb9a40f0d
Member variables are now named like_this_
David Demelier <markand@malikania.fr>
parents:
7
diff
changeset
|
228 return data_[index]; |
0 | 229 } |
230 | |
231 The `assert` macro is not meant to check that a function succeeded, this code | |
232 must not be written that way: | |
233 | |
234 assert(listen(10)); | |
235 | |
236 ### Exceptions | |
237 | |
238 You must use exceptions to indicate an error that was unexpected such as: | |
239 | |
240 - Failing to open a file, | |
241 - I/O unexpected errors, | |
242 - Parsing errors, | |
243 - User errors. | |
244 | |
245 You may use the C++ standard exceptions defined in the stdexcept header but if | |
246 you need to carry more data within your exception, you should derive from | |
247 `std::exception`. | |
248 | |
249 ### Free functions | |
250 | |
251 Basic utility functions should be defined in a namespace as a free function not | |
252 as a static member function, we're doing C++ not Java. | |
253 | |
254 Example: | |
255 | |
256 namespace util { | |
257 | |
258 std::string clean(std::string input); | |
259 | |
260 } // !util | |
261 | |
262 ### Variables initialization | |
263 | |
264 Use parentheses to initialize non primitive types: | |
265 | |
266 throw std::runtime_error("foo"); | |
267 | |
268 my_class obj("bar"); | |
269 | |
270 Use brace initialization when you want to use an initializer list, type | |
271 elision: | |
272 | |
273 std::vector<int> v{1, 2, 3}; | |
274 | |
275 foo({1, 2}); // type deduced | |
276 | |
277 return { "true", false }; // std::pair returned | |
278 | |
279 Use the assignment for primitive types: | |
280 | |
281 int x = 123; | |
282 bool is_valid = true; | |
283 | |
284 ### Classes | |
285 | |
286 Classes are usually defined in the following order: | |
287 | |
288 1. Public inner types (enums, classes), | |
289 2. Protected/private members | |
290 3. Public functions | |
291 | |
292 class foo { | |
293 public: | |
294 enum class type { | |
295 a, | |
296 b | |
297 }; | |
298 | |
299 private: | |
8
d7cbb9a40f0d
Member variables are now named like_this_
David Demelier <markand@malikania.fr>
parents:
7
diff
changeset
|
300 int member_{0}; |
0 | 301 |
302 public: | |
303 void some_function(); | |
12 | 304 }; |
0 | 305 |
306 ### Structs | |
307 | |
308 Do not use C structs unless you have very good reason to do so. If you want to | |
309 pack some data, just use `class` and make all fields public. | |
310 | |
311 class point { | |
312 public: | |
6
41dac98beeb2
Use inclass initializers
David Demelier <markand@malikania.fr>
parents:
3
diff
changeset
|
313 int x{0}; |
41dac98beeb2
Use inclass initializers
David Demelier <markand@malikania.fr>
parents:
3
diff
changeset
|
314 int y{0}; |
0 | 315 }; |
316 | |
317 ### Return | |
318 | |
319 The preferred style is to return early in case of errors. That makes the code | |
320 more linear and not highly indented. | |
321 | |
322 This code is preferred: | |
323 | |
11 | 324 if (a_condition_is_not_valid) |
0 | 325 return nullptr; |
11 | 326 if (an_other_condition) |
0 | 327 return nullptr; |
328 | |
329 auto x = std::make_shared<object>(); | |
330 | |
331 x->start(); | |
332 x->save(); | |
333 | |
334 return x; | |
335 | |
1
9bf9b4634339
Update return statement
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
336 Additional rules: |
9bf9b4634339
Update return statement
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
337 |
9bf9b4634339
Update return statement
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
338 - Do never put parentheses between the returned value, |
9bf9b4634339
Update return statement
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
339 - Do not put a else branch after a return. |
13
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
340 |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
341 ### Auto |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
342 |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
343 We encorage usage of `auto`, it reduces code maintainance as you don't need to |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
344 change your code when your rename types. |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
345 |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
346 ````cpp |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
347 auto it = std::find_if(v.begin(), v.end(), [&] (const auto& obj) { |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
348 return obj.key() == "foo"; |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
349 }); |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
350 |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
351 for (const auto& pair : a_map) |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
352 std::cout << pair.first << " = " << pair.second << std::endl; |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
353 ```` |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
354 |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
355 But do not use `auto` to write code like in python, this is not acceptable: |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
356 |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
357 ````cpp |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
358 auto o = my_object("foo"); |
4d6bf8b3446d
Add chapter about auto
David Demelier <markand@malikania.fr>
parents:
12
diff
changeset
|
359 ```` |