Skip to content
Reputeless edited this page Jun 17, 2017 · 25 revisions

Siv3D C++ Style Guide

命名規則

変数

✅ 変数名は小文字から始まる mixed-case

int32 score = 0;

double currentSpeed = 1.0;

bool isPlaying = false;

定数

✅ ユーザ API における定数は大文字から始まる mixed-case

constexpr double Pi = 3.14159265358979323846;

constexpr double QuarterPi = Pi / 4.0;

✅📃 内部実装における定数の命名規則は変数と同じ

constexpr int32 k = 20;

constexpr size_t maxSize = 1024;

列挙子

✅ 列挙子は大文字から始まる mixed-case

enum class SpecialFolder
{
	Desktop,

	Documents,

	LocalAppData,
}

📌 列挙子の名前が if を含む場合、例外的に if の前後をアンダースコアで区切る

enum class CopyOption
{
	Fail_if_Exists,

	Overwrite_if_Exists,
	
	Rename_if_Exists,
};

関数

✅ 非メンバ関数は大文字から始まる mixed-case

void Sleep();

void SetTitle();

WindowState GetWindowState();

✅ メンバ関数は小文字から始まる mixed-case

void Image::resize(int32 width, int32 height);

void Sound::setVolume(double volume);

Vec2 Vec2::movedBy(double x, double y);

📌 標準ライブラリのラッパークラスのメンバ関数などでは、単語をアンダースコアで区切る場合がある

bool String::starts_with(wchar ch);

size_t Array::count_if(Fty f);

void Grid::remove_rows();

仮引数

✅ 仮引数の命名規則は変数と同じだが、メンバ関数で他のメンバと同名になる場合は _ プレフィックスを付ける

struct Point
{
	int32 x;

	int32 y;

	Point(int32 _x, int32 _y)
		: x(_x)
		, y(_y) {}
};

名前空間

s3d 以下の名前空間は大文字から始まる mixed-case

namespace s3d
{
	namespace System
	{

	}

	namespace Window
	{

	}

	namespace Time
	{

	}
}

✅📃 s3d 名前空間内にある内部実装のための機能は detail 名前空間に入れる

namespace s3d
{
	namespace detail
	{
	
	}
}

クラス・構造体

✅ クラスと構造体の名前は大文字から始まる mixed-case

struct Date;

struct Circle;

class TextReader;

メンバ変数

✅ private メンバ変数は m_ プレフィックスをつける

class Stopwatch
{
private:

	bool m_isStarted = false;
};

class Image
{
private:

	Array<Color> m_data;
};

ループ変数

✅ 一般的なループでは i, k, m を使う

  • ⚠️ ji と誤読しやすいので避ける
for (int32 i = 0; i < 10; ++i)
{
	for (int32 k = 0; k < 5; ++k)
	{

	}
}

✅ 座標に関するループでは x, y, z を使う

for (int32 y = 0; y < height; ++y)
{
	for (int32 x = 0; x < width; ++x)
	{
		gird[y][x] = 0;
	}
}

✅ イテレータは it を使う

for (auto it = v.begin(); it != v.end(); ++it)
{

}

ソース・ヘッダファイル

✅ C++ ソースとヘッダファイルの名前は大文字から始まる mixed-case で、拡張子は .cpp と .hpp を使う

✅ 1 つのヘッダのみからインクルードされ、インラインメンバ関数の実装のみを記述したヘッダの拡張子は .ipp を使う


その他

✅ 略語やアクロニムは大文字を使う

  • 📌 例外: 単語が変数名の先頭にくる場合は全て小文字にする
class HTTPClient;

namespace MIDI;

unit8 midiMessage;

⚠️ 省略した名前はなるべく使わない

  • 📌 例外: pos (position), num (number), min (minimum), max (maximum) は省略してよい
// ❌ Vec2 dir;
Vec2 direction;

// ❌ Color col;
Color color;

// ❌ double len;
double length;

コーディングスタイル

インデント

✅ インデントはハードタブを用いる


波括弧

if / for / while / switch では波括弧を省略しない

if (n > 20)
{
	n = 20;
}

if / for / while / switch と関数定義での波括弧はオールマンスタイルを用いる

int32 Max(const int32 a, const int32 b)
{
	if (a > b)
	{
		return a;
	}
	else
	{
		return b;
	}
}

if / for / while / switch に続く ( の直前には半角スペースを入れる

while (System::Update())
{

}

関数

✅ 引数の区切りのカンマの後には半角スペースを入れる

void Resize(int32 x, int32 y);

✅ 関数宣言時、値渡しの仮引数が算術型か列挙型であれば const はつけない

int32 Max(int32 a, int32 b);

✅📃 内部実装における関数定義では、仮引数の値を変更しない場合、算術型や列挙型であっても const をつける

int32 Max(const int32 a, const int32 b)
{
	return a > b ? a : b;
}

クラス・構造体

✅ 特に理由が無ければ private メンバを public メンバより先に書く

✅ メンバ関数はコンストラクタ、デストラクタ、コピー演算子、その他の順に書く

✅ メンバ変数をメンバ関数よりも先に書く

struct Point
{
	int32 x = 0;

	int32 y = 0;
};

class Widget
{
private:
    
	int32 m_a = 0;
    
	int32 m_b = 0;
    
	void increment()
	{
		++m_a;

		++m_b;
	}

public:

	Widget() = default;

	Widget(const int32 a, const int32 b)
		: m_a(a)
		, m_b(b)
	{
		Console << L"Hello!";
	}
	
	~Widget()
	{
		Console <<L "Good Bye!";
	}

	Widget operator +(const Widget& widget) const
	{
		return Widget(m_a + widget.m_a, m_b + widget.m_b);
	}

	void update()
	{
		increment();
	}

	void print() const
	{
		Console << m_a << L", " << m_b;
	}
};

コメント

✅ ユーザ API には XML ドキュメントコメントを記述する

✅📃 内部実装では XML ドキュメントコメントを記述する必要はない

✅ コメントの本文では半角英数字と全角文字の間には半角スペースを入れる

/// <summary>
/// マルチバイト ASCII 文字列をワイド文字列に変換します。
/// </summary>
/// <param name="asciiStr">
/// ASCII 文字で構成されたマルチバイト文字列
/// </param>
/// <remarks>
/// Widen() 関数より高速に動作します。
/// </remarks>
/// <returns>
/// 変換されたワイド文字列
/// </returns>
String WidenAscii(CStringView asciiStr);

プリプロセッサ ディレクティブ

✅ # include ディレクティブは

  • C 言語由来の C++ 標準ライブラリ <cstdlib>, <cmath>, <cassert>
  • C++ 標準ライブラリ <vector>, <array>, <random>
  • Siv3D・サードパーティライブラリ "Fwd.hpp", "String.hpp", "Format.hpp"

の順にインクルードする

✅ ディレクトリ区切り文字は / を 使う

# の直後には半角スペースを入れる

# pragma once
# include <vector>
# include "Fwd.hpp"

✅ インクルードガードには # pragma once のみを用いる

✅ MSVC の警告抑制には S3D_DISABLE_MSVC_WARNINGS_PUSH(warnings), S3D_DISABLE_MSVC_WARNINGS_POP() マクロを使う

S3D_DISABLE_MSVC_WARNINGS_PUSH(4100)

//

S3D_DISABLE_MSVC_WARNINGS_POP()

✅ プラットフォーム間の差異を吸収するマクロは先頭の # を該当箇所のスコープ { と同じインデントにし、その内側のコードは前後に空白行を入れる

namespace s3d
{
# if defined(SIV3D_TARGET_MACOS)

	namespace detail
	{
		static __inline__ uint64 rdtsc()
		{
			uint32 hi, lo;
			__asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));
			return static_cast<uint64>(lo) | (static_cast<uint64>(hi) << 32);
		}
	}

# endif

	inline void AlignedFree(void* p)
	{
	# if defined(SIV3D_TARGET_WINDOWS)

		::_aligned_free(p);

	# else

		::free(p);

	# endif
	}
}

演算子

✅ 演算子オーバーロードの定義では、演算子の前に半角スペースを入れ、後ろには半角スペースを入れない

Point& operator +=(const Point&);

size_t 型以外の整数型は、Siv3D の Types.hpp が提供する型 (s3d::int32 等)を使う

int32 n = 0;

その他

✅ ネストはなるべく浅くする

✅ 関数のオーバーロードは引数が単純なものを先に書く

typedef ではなく using を使う

template では typename ではなく class を使う

✅ ポインタには 0NULL ではなく nullptr を使う