Is it considered good practice to structure single-file/header-only libraries in C++ such that they are conditionally either the header or the implementation? For example,
#ifndef LIBRARY_HEADER_HPP_
#define LIBRARY_HEADER_HPP_
// Header
struct Test {
void test();
};
#endif // LIBRARY_HEADER_HPP_
#ifdef LIBRARY_IMPLEMENTATION_
#undef LIBRARY_IMPLEMENTATION_
// Implementation
void Test::test() {
}
#endif // LIBRARY_IMPLEMENTATION_
The user of the library would therefore #define LIBRARY_IMPLEMENTATION before one #include "Library.hpp" in a single implementation file, to avoid multiple definitions.
I've seen this strategy used in C libraries (STB comes to mind), but I was wondering whether this would be considered idiomatic in modern C++ (or if there are better strategies for creating single-file/header-only libraries).
Related
For example if I have a header like this:
class Example {
int a;
#if TEST
int b;
#endif
};
how can I distribute my binary library, to avoid user getting an ABI problem?
P.S. I asked this because I used a library and it is compiled with the definition TEST, while I'm not define it when I include the header, which leads to the size in header does not match with the library. I'm interesting how to avoid this if I'm going to distribute some libraries someday.
What you could do is to provide a init function for your library and define in the header, and a function like ensure_TEST_is_set that is defined in library/binary.
void ensure_TEST_is_set();
void init_library() {
#if TEST
ensure_TEST_is_set();
#endif
}
void ensure_TEST_is_set() {
#ifndef TEST
throw std::runtime_error("Library not ABI compatible, TEST is not matching");
#endif
}
So the ensure_TEST_is_set is shipped part of the binary, and depending on if TEST was set when compiling or not, it will throw an exception when called.
The #if TEST in the init_library - as it is defined in the header - will be evaluated by everytime the header is used.
I'm using an external C library inside a C++ project.
The header contains a struct with a variable named class:
#ifdef __cplusplus
extern "C" {
#endif
struct something_t {
...
sometype class;
};
#ifdef __cplusplus
}
#endif
g++ does not like this and complains about "error: expected identifier before ';' token".
What options do I have?
I could rename class, but that's cumbersome and breaks upstream compatibility.
I could ask the upstream project to rename the variable, but that may be difficult.
I could redefine class in the header using the preprocessor: #define class class_ Are there any side effects?
Any other suggestions?
What's the best way to handle this situation?
Result: Based on the prevailing preference for option 2, I finally chose to initiate a renaming in the upstream library.
As others already mentioned in comments, the best option is to write another C API layer around that stuff, that uses the other API only internally.
Anything related to this offending struct definition should be exported through opaque pointers only.
In C++ you can use the cleaned up C-API then.
Here's a small sketch:
ThirdParty.h (contains offending code to compile with c++)
#ifdef __cplusplus
extern "C" {
#endif
struct something_t {
...
sometype class;
};
struct something_t* CreateSomething(); // Does memory allocation and initialization
void DoSomething(struct something_t* something);
#ifdef __cplusplus
}
#endif
MyApiWrapper.h
#ifdef __cplusplus
extern "C" {
#endif
typedef void* psomething_t;
struct psomething_t MyCreateSomething(); // Does memory allocation and initialization
void MyDoSomething(psomething_t something);
#ifdef __cplusplus
}
#endif
MyApiWrapper.c
#include "ThirdParty.h"
struct psomething_t MyCreateSomething() {
psomething_t psomething = (psomething_t)CreateSomething();
return psomething;
}
void MyDoSomething(psomething_t something) {
DoSomething((struct something_t*)psomething);
}
Regarding your considered solutions
I could ask the upstream project to rename the variable, but that may be difficult
You certainly should report that bug to let them know. If it's a git-hub hosted project prepare a pull request.
Anyways be prepared that they might not be responsive timely, and you should always have the above mentioned "plan B". It will work regardless ...
I could redefine class in the header using the preprocessor: #define class class_ Are there any side effects?
It could be a viable way, if any place where this particular symbol (class) appears is plain c code and no other parts of the 3rd party c code (e.g. as library) depends on that symbol (which is unlikely).
I'm creating an header-only C++11/14 library and I'm not sure on how I should handle #include directives between library files.
Should I try to group as many #include directives as possible in the user-oriented module header file or should internal files include files they require (sometimes repeating the same includes)?
Approach A:
In this approach, the module header file includes all required dependencies and then includes the implementations. The implementations' header files do not include anything by themselves.
// Library/Module/Module.hpp
// This file is intended to be included by the user in his projects.
#ifndef MODULE
#define MODULE
#include <vector>
#include "Library/Module/Impl/SharedDependency.hpp"
#include "Library/Module/Impl/Class1.hpp"
#include "Library/Module/Impl/Class2.hpp"
#endif MODULE
-
// Library/Module/Impl/SharedDependency.hpp
#ifndef SHARED_DEPENDENCY
#define SHARED_DEPENDENCY
inline void sharedFunc() { }
#endif
-
// Library/Module/Impl/Class1.hpp
#ifndef CLASS1
#define CLASS1
// No need to include "SharedDependency.hpp", as it will be included by
// the module header file. Same applies for <vector>.
struct Class1
{
std::vector<int> v;
Class1() { sharedFunc(); }
};
#endif
-
// Library/Module/Impl/Class2.hpp
#ifndef CLASS2
#define CLASS2
// No need to include "SharedDependency.hpp", as it will be included by
// the module header file. Same applies for <vector>.
struct Class2
{
std::vector<int> v;
Class2() { sharedFunc(); }
};
#endif
Approach B:
In this approach, the module header file includes only the implementation headers. If the implementation headers require additional includes, they include the files themselves (recursively), sometimes repeating the same include.
// Library/Module/Module.hpp
// This file is intended to be included by the user in his projects.
#ifndef MODULE
#define MODULE
#include "Library/Module/Impl/Class1.hpp"
#include "Library/Module/Impl/Class2.hpp"
#endif MODULE
-
// Library/Module/Impl/SharedDependency.hpp
#ifndef SHARED_DEPENDENCY
#define SHARED_DEPENDENCY
inline void sharedFunc() { }
#endif
-
// Library/Module/Impl/Class1.hpp
#ifndef CLASS1
#define CLASS1
#include <vector>
#include "Library/Module/Impl/SharedDependency.hpp"
struct Class1
{
std::vector<int> v;
Class1() { sharedFunc(); }
};
#endif
-
// Library/Module/Impl/Class2.hpp
#ifndef CLASS2
#define CLASS2
#include <vector>
#include "Library/Module/Impl/SharedDependency.hpp"
struct Class2
{
std::vector<int> v;
Class2() { sharedFunc(); }
};
#endif
What is the best approach?
Intuitively, I think Approach A is the best, as it avoids repeating the same includes and makes clear what files need to be included before the other files. The biggest drawback is, though, that syntax highlighting stops working in my IDE (QT-Creator), in the implementation files with no include directives.
EDIT:
This question was voted to be closed for the reason "opinion based". I disagree, because in a large header-only project such as my library including files may take a lot of compile time. Therefore, approach A may be faster than approach B, or the opposite.
Approach B is actually the best approach, since including the same header multiple times does not produce any observable compilation time increase, but is advantageous for the following reasons:
Modern IDEs can use libclang or proprietary solutions to parse the #include directives and provide code-aware syntax highlighting and autocompletion features.
As mentioned by TemplateRex, it becomes much easier to verify a sane build process. CMake, for example, provides macros that automatically generate a test for every header.
As mentioned by Alf, it is good practice to have every file include all the headers it depends on - users of the library can then "cherry-pick" header files they require, instead of being unexpectedly force to manually include a parent header.
I would like to know if this is the correct way to port a C library to C++; for this example I wrote a 2 line C header with a function and a typedef managing a pointer.
lib.h
#ifndef LIB_H
#define LIB_H
#include <math.h>
double foo(double a) { return (log(a)); }
typedef double (*PtoFoo)(double);
#endif // LIB_H
lib.hpp
#ifndef LIB_HPP
#define LIB_HPP
namespace lib {
extern "C" {
#include "lib.h"
}
}
#endif // LIB_HPP
and a little test in C++11
#include <iostream>
#include "lib.hpp"
#include <functional>
int main() {
// call to the function
std::cout << lib::foo(42354.343) << "\n";
// trying the pointer to function type
lib::PtoFoo ptr = lib::foo;
std::function<double(double)> f(ptr);
std::cout << f(342.4) << "\n";
return (0);
}
right now my attention is focused on pointers, function pointers and functions, but in general I would like to know if this is the correct way to port standard C code to C++ and using the new c++ interface with namespaces without possible backfires .
Yes, that is the correct way to do it.
Alternatively, you can use the __cplusplus preprocessor token to define the C++ interface in the same header file:
#ifdef __cplusplus
namespace lib {
extern "C" {
#endif
typedef ...
#ifdef __cplusplus
}
}
#endif
The advantage of this approach is that only a single header file is required.
As I commented, C++ is designed to be compatible with C, so just wrapping your C library headers with the appropriate extern "C" { and } /* end extern "C"*/; is enough.
However, you may want to design a C++ friendly interface to your library. This requires some thoughts, and some code (most of it in C++ specific header files). For instance, you may want to provide interfaces using C++ object, overloading, operator, and template facilities.
I can't help more, but look for examples at: libonion and its C++ bindings, GTKmm which is a large C++ binding to GTK (and companion libraries like Glib...), the C++ class interface to gmplib, or even the newest C++11 standard thread library (i.e. std::thread etc, etc...) which could be viewed as a clever C++ wrapping of pthreads ....
I believe that each library could have its own C++ wrapping... How to design that is up to you... (depends a lot on the wrapped library, your available time, and your fluency with C++...).
I need to maintain a project that supports running on Linux and Windows. Some codes using preprocessor directives like this are fine.
#ifdef _WIN32 // _WIN32 is defined by Windows 32 compilers
#include <windows.h>
#else
#include <unistd.h>
#endif
But some are the actual implementation, which I would like to prevent using preprocessor directives.
void Foo()
{
#ifdef _WIN32 // _WIN32 is defined by Windows 32 compilers
code for windows
#else
code for Linux
#endif
some common code...
#ifdef _WIN32 // _WIN32 is defined by Windows 32 compilers
code for windows again
#else
code for Linux again
#endif
}
So things get convoluted and harder to maintain. Is there any better way?
The traditional way is to "hide" all the code that is specific to any OS in wrapper functions - you can either do that in complete functions that do a higher level functionality - e.g. have a function that returns all directory entries based on a given path as input, or implement the individual base-functions, e.g. start_read_directory(path), read_dir_entry(), end_read_directory() - that's just an example functionality, the same principle(s) can be applied on almost any system specific functionality. Wrap it enough, and you wouldn't be able to tell what you are programming for.
In essence, you are doing it wrong if you have a lot of #ifdef in the code itself.
Handle the OS specifics from the build system, not the code. For instance, have two versions of Foo.cpp: one that gets compiled on Linux and another on Windows. Ideally, the header file will be common and all function signatures identical.
You can use a simplified version of the factory pattern.
Have a common interface
class MyClass
{
public:
virtual void Foo() = 0;
};
And for each platform you create a specific class
#import <windows.h>
class MyClassWindows : MyClass
{
public:
virtual void Foo() { /* Do something */ }
};
#import <linux.h>
class MyClassLinux : MyClass
{
public:
virtual void Foo() { /* Do something */ }
};
Then when you need this class, you use your factory:
class MyClassFactory
{
public:
static MyClass* create()
{
#if defined _WIN32
return new MyClassWindows();
#elif defined _LINUX
return new MyClassLinux();
#endif
}
}
There a many variants of this methods, including defining the MyClassFactory::create method in the .cpp of each platform-specific class and only compiling the .cpp for the appropriate platform. This avoids all preprocessing directives, the switching is made by choosing the correct implementation file.
A common pattern would be to provide system independent header files, and platform-specific implementation files.
Nothing platform specific in the header:
class Foo
{
...
};
In two different implementation files, foo_linux.cpp
Foo::Foo() { .. linux code }
foo_windows.cpp
Foo::Foo() { .. windows code }
and maybe platform independent implementation in foo.cpp
void Foo::plat_independent_function()
Your platform builds then link in foo.cpp and foo_platform.cpp
A possibility for the implementation of this is to use the PIMPL idiom, where your class just publishes the "interface" and declares a meaningless pointer to an implementation class (in its dark, hidden and private corner) and the build system takes care of pulling in the correct platform dependent code for the class containing the implementation of your PIMPL.