C++ Style
This section defines stylistic, structural, and formatting standards for C++ source code.
Naming Conventions
Naming conventions are not covered in this section.
See Naming Conventions.
Formatting
Intricate uses .editorconfig to enforce code-styling. In Visual Studio, the code formatter can be run by pressing the hotkey chord Ctrl+K, Ctrl+D on an open file.
Info
All formatting rules denoted by a * are automatically applied by .editorconfig or Visual Studio.
Indentation
- Use 4 spaces per indentation level.*
- Do not use tab characters.
- Continuation lines should be indented once with respect to the current indentation level.*
Tip
Pressing the tab key will add 4 spaces instead of a tab character for indentation when .editorconfig is enabled.
Line Length
- Soft limit: 130 characters
- Split long expressions across multiple physical lines if required.
- Break long expressions at logical boundaries (e.g. in-between parameters of a method call.)
Whitespace and Newlines
- Use exactly one blank line between:
- Method definitions
- Class members grouped by purpose
- Logical blocks of code grouped by purpose
- Do not leave trailing whitespace.*
- Use exactly one space after commas and semicolons inside parameter lists and other constructs.*
- Use exactly one space before and after binary operators.*
- Example:
a + b,x == 3,value * 2 - No spaces for:
- Indexing:
arr[i] - Unary operators:
-x,!flag,~mask,++i,i-- - Scope resolution:
std::string
- Indexing:
- Example:
- Insert a final newline at the end of source files.*
Warning
More than one blank line should never be used anywhere other than in-between the #include directives and the namespace declaration.
Braces
- Use the Allman style*:
void Foo()
{
if (true)
{
// Block-bodies covering multiple lines must always have the opening brace on a newline.
}
}
- Omit the braces for single-line control-flow blocks:
- Empty function bodies should be defined as:
- Multi-line lambda function bodies should have their braces indented*:
Helpers::FetchExecuteIfValid<Scene>(nativeID, [&](const Ref<Scene>& scene)
{
scene->DestroyEntity(entityID);
});
Control Flow Blocks
- Do not inline control-flow blocks:
else,catch,finallyandcasemust always appear on its own line.- Prefer ternary expressions over simple
if-elseblocks.
Pointers and References
- Place
*and&adjacent to the type*:
- Multiple declarations per line are discouraged.
Preprocessor Directives
- Preprocessor directives should be indented and follow an independent indentation level:
#ifdef _IE_ENABLE_LOGGING
# define _IE_NATIVE_USE_TYPE_TRACKING
#endif // _IE_ENABLE_LOGGING
#ifdef _IE_NATIVE_USE_TYPE_TRACKING
# include <IntricateEngine/Core/Core.hpp>
#endif // _IE_NATIVE_USE_TYPE_TRACKING
- Prefer inserting ending comments to preprocessor
#ifdirectives as seen above.
File Structure
Header File Layout
-
Order elements in the following sequence unless justified otherwise:
- File header, version history or copyright (if applicable)
- Header guard (
#pragma once) - Includes
- Module imports
- Two blank lines
- Namespace declaration
- Enum declaration(s)
- Class/struct declaration(s) (in order of dependency)
Type layout:
- Constants
- Nested Types
- Constructors (
public→protected→private) - Destructor
- Public methods
- Overrides
- Specializations
- Conversion operators
- Operator overloads
- Public static constants
- Public static methods
- Protected methods
- Private methods
- Private static methods
- Instance variables (
public→protected→private)
-
Access specifiers should be grouped and not interleaved.
- Forward-declarations should be made in the appropriate scope or just before its first reference.
Source Files
- Order elements in the following sequence unless justified otherwise:
- Precompiled header include
- Includes
- Module imports
- Two blank lines
- Namespace declaration
- Constants
- Nested namespaces with helpers (such as a
Utilsnamespace) - Internal global variables
- Internal methods
- Static member variable definitions
- Class/struct methods (in the order seen in the header file)
Include Directives
- Place
#includedirectives outside of namespaces. - Local includes should be specified using quotes:
#include "MyHeader.hpp". - Non-local includes should be specified using angle brackets:
#include <IntricateEngine/Math/Vector2.hpp>. - Headers should always be included from top-to-bottom in terms of folder depth.
- Group and sort includes alphabetically in the following order:
- Precompiled header/local includes
- Paired header (for a source file)
- Current project's headers
- Intricate headers
- Vendor headers
- STL headers
- C standard headers
- Platform headers (
d3d11.h,windows.h,sys/mman.h)
- Insert two blank lines after the final
#includedirective before the namespace declaration.
Comments
Documentation
Use XML documentation comments for:
- Public types
- Public and protected members
Note
We may switch to Doxygen comments soon.
Commenting Style
See: Comments.