First, break down the project into a set of components. For example, for a game engine, you might break it down into the following components:

  • core
  • renderer
  • physics
  • audio

You can break each component down further, if you desire.

Now, have a src and an include folder, with subfolders for each of your components:

- include
    - core
    - renderer
    - physics
    - audio
- src
    - core
    - renderer
    - physics
    - audio

Now, put your .h files in the correct subfolder of the include folder, and put your .cpp files in the correct subfolder of the src folder:

- include
    - core
        - **Entity.h**
        - **Vector.h**
    - renderer
        - **BatchDrawer.h**
    - physics
    - audio
- src
    - core
        - **Entity.cpp**
        - **Vector.cpp**
    - renderer
        - **BatchDrawer.cpp**
    - physics
    - audio

Generally, try to follow an object oriented approach, where you try to split a particular component into a set of classes. Then create a .h file for the class declaration, and .cpp file for the class definition. You already know where to put .h and .cpp files.

If you just have a set of related free functions, again, put the declarations in a .h file and definitions in a .cpp file.

If you have a template function/class, put the declaration and definition in the same .h file. You can “split” the .h file into a .h and a .tpp file, if you wanna seperate the declaration and definition. You would put the declaration in the .h file and the definitions in the .tpp file. You include the .tpp file at the end of the .h file. You can still imagine that you have a single .h file, but it’s just split into two files.

If you are developing a library/framework, you might want to keep all your classes/functions (whether template or not) in a namespace, to avoid polluting the global namespace of the end user. If you are developing a very large project, even if it is not a library, you might want to do the same, to avoid name collisions with yourself or libraries you are using. In this case, you may put different components into different namespaces. If you’re project is relatively small and you’re not developing a library/framework, you can just put everything in the global namespace.

If you are using libraries, put them in a lib or dependencies folder:

- dependencies
    - glm
    - glew

You would obviously need to adjust your header search path, library search path, and linker options to be able to use the libraries.

You may also want the following:

- docs              # put documentation here
- tests             # put tests here (you may want subfolders for each component)
- CMakeLists.txt    # build system file
- README.md         # project's main readme

Putting this all together, you get the following:

  • include
    • core
      • Entity.h
      • Vector.h
    • renderer
      • BatchDrawer.h
    • physics
    • audio
  • src
    • core
      • Entity.cpp
      • Vector.cpp
    • renderer
      • BatchDrawer.cpp
    • physics
    • audio
  • dependencies
    • glm
    • glew
  • docs
  • tests
  • CMakeLists.txt
  • README.md

You may see other structures being used in the wild, like so:

- src
    - core
        - **Entity.h**
        - **Entity.cpp**
        - **Vector.h**
        - **Vector.cpp**
    - renderer
        - **BatchDrawer.h**
        - **BatchDrawer.cpp**
    - physics
    - audio

Notice that the .h and .cpp files are in the same folder. This is fine, but if your project is a library you may want to seperate your .h and .cpp files into seperate folders, so that the end user can easily see which files are the headers and which are the source files. Often your end user is not interested in the implementation of your libraries, and sometimes they won’t even want your source files. They may just want your header files and some binaries to link to. When your header/source files are split into seperate folders, it is easy to just give end users the headers.