This project uses vcpkg to install dependencies. Make sure you already have
vcpkg and the Vulkan SDK (not required if the required tools are already
installed separately) set up, then choose one of the following:
cd <project directory>
cmake --preset debug
cmake --build --preset debugcd <project directory>
cmake --preset release
cmake --build --preset releasecd <project directory>
cmake --preset rel-with-deb-info
cmake --build --preset rel-with-deb-infocd <project directory>
cmake --preset min-size-rel
cmake --build --preset min-size-relThe presets use clang++ by default.
After configuring the project, a compile_commands.json symlink will be created
in the project root, which allows it to be easily picked up by clangd.
- When you change the warning flags to disable for Clang in
.clangdinCompileFlags.Add, remember to sync those changes toCMakeLists.txtin theCLANG_WARNINGSvariable as well.
This project uses Boost's
LEAF for
error handling instead of exceptions. It offers a middle ground between
exceptions and Rust's Result. Exceptions make error handling implicit, and it
becomes hard to tell which part of the code can throw errors and which part
handles them. Rust's Result makes error handling explicit, and functions
returning a Result must specify what type of error it can return.
boost::leaf::result makes error handling explicit, but doesn't require
functions to return a specific error type. Compare Result<T, E> with
boost::leaf::result<T>. The latter doesn't specify the error type.
This can be a good or a bad thing, though. It offers more flexibility over
Result, but makes it unclear what error type to handle if you call a function
returning a boost::leaf::result, since boost::leaf::result allows you to
attach an arbitrary number of error objects of arbitrary types. To make it more
sensible, this project applies following rules on top of LEAF:
-
Any function returning a
boost::leaf::result, in the case of an error, must return an enum as an error object that specifies the type of error that occurred, called the error enum variant. The type of the error enum variant must be documented in the function's documentation, called the error enum type. -
Because C++ doesn't have Rust-like enums that allow you to attach extra information along with an enum variant, if the enum error variant requires extra information to fully describe the error, there should be an error info object that gets returned along with that error enum variant in the
boost::leaf::result. The type of the error info object is called its error info type, and is always named as<error enum type name><error enum variant name>Info. An error info object doesn't have to always accompany the error enum variant if the error enum variant only requires extra information sometimes. -
There can be more than the above two error objects attached to a
boost::leaf::resultto return information not specific to any particular error type. For example, theBOOST_LEAF_NEW_ERRORmacro always attaches an extrae_source_locationobject. -
If a
boost::leaf::resultneeds to wrap anotherboost::leaf::result, store the wrappedboost::leaf::resultin a error info type, and document which function returns that wrappedboost::leaf::result, so users know how to handle it.
For example, if you have this function:
auto read_file(const std::string &path) -> boost::leaf::result<File>;It may return this error enum type:
enum class FileReadError { FileNotFound, NoPermission };read_file should document that FileReadError is the error enum type it
returns in case of an error.
If FileReadError::FileNotFound needs to describe which path segment doesn't
exist, it can use this error info type:
struct FileReadErrorFileNotFoundInfo {
std::string non_existent_path_segment;
};Then, to handle all FileReadError variants, you can accept the type
FileReadError in the handler. To handle FileReadError::FileNotFound
specifically and also acquire its FileReadErrorFileNotFoundInfo, you can
accept boost::leaf::match<FileReadError, FileReadError::FileNotFound>, FileReadErrorFileNotFoundInfo in the handler.