ftz.Lyberta.net

Modern C++ goodness

C++ formatting

Formatting

Indent blocks with 1 tab

{
	/* ... */
}

Use spaces to separate tokens in expression

int a = b + c;

Separate function arguments with 1 space

Foo(a, b, c);

Put asterisk or ampersand near the type

MyType* pointer = nullptr;
MyType*& reference_to_a_pointer = pointer;

Format if like this

Avoid Yoda conditionals. Always put the statement code in a separate block to avoid confusion.

if (a == 5)
{
	/* ... */
}
else
{
	/* ... */
}

Format switch like this

switch (something)
{
	case A:
	{
		/* ... */
		break;
	}
	case B:
	{
		/* ... */
		break;
	}
	default:
	{
		/* ... */
	}
}

Format for like this

Keep in mind that most indexing operations expect std::size_t and not int. In range-based for loop you should use const auto& if you don’t plan to modify the elements.

for (std::size_t i = 0; i < something; ++i)
{
	/* ... */
}

// Here we modify i
for (auto&& i : container)
{
	/* ... */
}

// Structured binding + non modifying observation
for (const auto& [key, value] : somemap)
{
	/* ... */
}

Format while like this

while (something)
{
	/* ... */
}

do
{
	/* ... */
}
while (something);

Format functions like this

// Header file
void Foo(Type1 a, int b = 0);

template <typename T>
	requires std::is_integral_v<T>
void Bar(T& t);



// Source file
void Foo(Type1 a, int b)
{
	/* ... implementation ... */
}

template <typename T>
	requires std::is_integral_v<T>
void Bar(T& t)
{
	/* ... implementation ... */
}

Format enums like this

enum Something
{
	FirstValue,
	SecondValue,
	ThirdValue = 1337,
	FourthValue
};

enum class SomethingElse : unsigned short
{
	NoReally,
	ThisIs,
	CompletelyDifferent
};

Format structs like this

struct MyStruct
{
	int a;
	float b;
	std::string c;
};

Format classes like this

// Header file
class MyClass : public MyParent
{
public:
	using InnerType = std::uint8_t;

	MyClass();
	MyClass(InnerType a);
	MyClass(const MyClass&) = default;
	MyClass(MyClass&&) = delete;
	MyClass& operator=(const MyClass& other);
	MyClass& operator=(MyClass&& other);
	static int SomeStaticFunc() noexcept;
	virtual bool PureFunc() const noexcept = 0;
protected:
	virtual InnerType SomeFunc() const;
private:
	InnerType membervar;

	void SomePrivateFunc();

	friend void SomeGlobalFunc();
	friend class SomeOtherClassTemplate<InnerType>;
};

template <typename T>
MyClassTemplate
{
public:
	void DoThis(int a);

	template <typename U>
		requires std::is_trivial_v<U>
	U DoThat(long long b);
};



// Source file
template <typename T>
void MyClassTemplate<T>::DoThis(const int a)
{
	/* ... */
}

template <typename T> template <typename U>
	requires std::is_trivial_v<U>
U MyClassTemplate<T>::DoThat(const long long b)
{
	/* ... */
}

Format namespaces like this

namespace Outer::Inner
{

/* ... */

namespace OnlyPartialFile
{

/* ... */

}
}

Include headers like this

#include <iostream>
#include <string>

#include <SomeOtherLibrary/SomeHeader>

#include "LocalHeader.h"

Limit maximum line size to 80 characters

Indent continued lines with 1 tab. When breaking up the line try breaking it after the comma. Don’t separate the types and names of variables.

// Bad
void Foo(int a, int
b);

// Good
void Foo(int a,
	int b);

When breaking up a complex expression break it after the operator.

// Bad
auto a = b
	+ c;

// Good
auto a = b +
	c;

When breaking up the member function name definition break it after ::

void MyLongClassName::
	VeryLongFunctioName();

Complex concept requirements must be indented twice relative to the first line of a template.

template <typename T>
	requires SomeVeryLongConcept<T> &&
		AnotherLongConcept<T> &&
		AndAnotherOne<T>
void Foo(const T& a);

Naming

Local variables and member variables are snake_case

int variable1;
std::string some_buffer;

Constants are CamelCase

constexpr int MagicNumber = 42;

User-defined types are CamelCase

using MyTypeAlias = int;
enum MyEnum {};
struct MyStruct;
class MyClass;

Template typenames and concepts are CamelCase

template <MyConcept T>
bool CheckSomething(const T& input);

Macros are all uppercase with underscores

#define MY_VERY_EVIL_MACRO(a) U ## a

Function names should start with the verb and be CamelCase

int DoSomething();

Documentation

Start every file with the following:

/// \file
/// \brief <File synopsis>
/// \author <author>
/// \copyright <license name>

Document functions like this:

/// \brief Does something
/// \param[in] foo Input foo.
/// \param[in,out] baz Baz which is altered inside the function.
/// \return Returns Foo.
/// \throw std::invalid_argument If something is wrong.
/// \note Some important text.
Foo DoFoo(Bar bar, Baz& baz);

If a header file describes a class, use both \brief and \details fields and leave an empty line after.

// In file Foo.h

/// \brief A foo.
/// \details A foo is a placeholder name.

class Foo
{
	...
};

For one line entities use ///< style docs, for non-primary structs use only \brief

When breaking a ///< comment replace it with /// \brief.

const std::uint8_t SomeConstant = 42; ///< A very important number.

/// \brief A foo struct.
struct Foo
{
	int bar; ///< Holds bar.
	std::string baz; ///< Holds baz.
	/// \brief Holds qux.
	AVeryLongName qux;
};