This is a template for C++ projects.

Contents

Directory Structure

Markdown

Markdown is a lightweight markup language for text formatting.

Each project should include a readme file with the following information:

README.md

# HelloWorld

This application prints *Hello World!* on screen.
The intention is to have a template for C++ projects.

## How to build

### CMake

```
mkdir build
cd build
cmake ..
cmake --build .
```

### Conan

```
mkdir build
cd build
conan install --build=missing ..
conan build ..
```

## Running the tests

```
cd build
ctest
```

## Usage

```
cd build
./bin/hello [name]
```

CMake

CMake is the de facto standard build system for C++.

CMakeLists.txt

cmake_minimum_required(VERSION 3.1)

project(HelloWorld)

include(CTest)
include(${CMAKE_BINARY_DIR}/conan_paths.cmake OPTIONAL)

find_package(Boost REQUIRED)

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

include_directories(src)
add_subdirectory(src)

if(BUILD_TESTING)
    enable_testing()
    add_subdirectory(test)
endif()

src/CMakeLists.txt

add_subdirectory(util)

set(hello_SOURCES
    main.cpp)
add_executable(hello ${hello_SOURCES})
target_link_libraries(hello util)

install(TARGETS hello
        RUNTIME DESTINATION bin)

src/util/CMakeLists.txt

set(util_HEADERS
    simple_replacer.hpp)
set(util_SOURCES
    simple_replacer.cpp)
add_library(util ${util_SOURCES} ${util_HEADERS})
set_target_properties(util PROPERTIES PUBLIC_HEADER "${util_HEADERS}")
target_include_directories(util PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(util ${Boost_LIBRARIES})

install(TARGETS util
        ARCHIVE DESTINATION lib
        LIBRARY DESTINATION lib
        PUBLIC_HEADER DESTINATION include/util)

test/CMakeLists.txt

add_subdirectory(util)

test/util/CMakeLists.txt

add_executable(simple_replacer_test simple_replacer_test.cpp)
target_link_libraries(simple_replacer_test util)
add_test(NAME simple_replacer COMMAND simple_replacer_test)

Conan

Conan is a package manager for C++.

conanfile.py

from conans import ConanFile, CMake, tools

class HelloWorldConan(ConanFile):
    name = "HelloWorld"
    settings = "os", "compiler", "build_type", "arch"
    options = {
        "shared": [True, False],
        "build_tests": [True, False]
    }
    default_options = {
        "shared": False,
        "build_tests": True
    }
    build_requires = (
        "boost/1.67.0@conan/stable"
    )
    generators = "cmake_paths"
    scm = {
        "type": "git",
        "url": "auto",
        "revision": "auto"
    }

    def set_version(self):
        try:
            git = tools.Git(folder=self.recipe_folder)
            tag = git.get_tag()
            if tag:
                if tag[0] == 'v':
                    self.version = tag[1:]
                else:
                    self.version = tag
            else:
                self.version = git.get_revision()[:7]
        except Exception as ex:
            print("Exception in set_version(): "+str(ex))
            self.version = "undef"

    def _configure_cmake(self):
        cmake = CMake(self)
        #cmake.generator = "Ninja"
        if not self.options.build_tests:
            cmake.definitions['BUILD_TESTING'] = 'OFF'
        cmake.configure()
        return cmake

    def build(self):
        cmake = self._configure_cmake()
        cmake.build()

    def package(self):
        cmake = self._configure_cmake()
        cmake.install()

Git

Git is a version control system that tracks changes in code.

The build directory is excluded from tracking changes.

.gitignore

build

Clang-Format

Clang-Format is a tool to format code.

.clang-format

BasedOnStyle: WebKit
NamespaceIndentation: None

Header Files

src/util/simple_replacer.hpp

#pragma once

#include <string>

namespace util {

class SimpleReplacer {
public:
    explicit SimpleReplacer(const std::string& content);
    virtual ~SimpleReplacer();

    void replaceAll(const std::string& search, const std::string& replace);
    std::string getContent() const;

private:
    std::string content_;
};

} // namespace util

Source Files

src/main.cpp

#include "util/simple_replacer.hpp"
#include <iostream>
#include <string>

int main(int argc, char* argv[])
{
    std::string msg("Hello World!");
    if (argc >= 2) {
        util::SimpleReplacer replacer(msg);
        replacer.replaceAll("World", argv[1]);
        msg = replacer.getContent();
    }
    std::cout << msg << std::endl;
}

src/util/simple_replacer.cpp

#include "simple_replacer.hpp"
#include <boost/algorithm/string.hpp>

namespace util {

SimpleReplacer::SimpleReplacer(const std::string& content)
    : content_(content)
{
}

SimpleReplacer::~SimpleReplacer() = default;

void SimpleReplacer::replaceAll(const std::string& search,
    const std::string& replace)
{
    boost::replace_all(content_, search, replace);
}

std::string SimpleReplacer::getContent() const
{
    return content_;
}

} // namespace util

test/util/simple_replacer_test.cpp

#include "util/simple_replacer.hpp"

int main()
{
    std::string content("Just a test.");
    util::SimpleReplacer replacer(content);
    replacer.replaceAll("a", "another");
    std::string result = replacer.getContent();
    std::string expected("Just another test.");
    if (result == expected) {
        return 0;
    }
    return 1;
}