I have a couple of questions, and that is what is the reason for only having .h files with no .cpp files in the main part of the microframework? Did something force you to do it that way or was it done like that because you like that code structure?
Inlining everything is bad because:
- it makes the binary much bigger.
- the smallest code change forces library users (applications) to be recompiled.
For libraries it's usually better to go to the other extreme: hide as much code and data as possible in the source files. See, for example, https://en.wikipedia.org/wiki/Opaque_pointer. It greatly reduces the need for applications to be recompiled when the library is updated.It's actually very unusual to put all function implementations inline (edit: as in, inside the class declaration) in C++. I wonder whether the author is a heavy Java user.
The language says that's just a suggestion to the compiler, right? Does any compiler actually inline for non-trivial methods?
// header.hpp
inline int f(int x) { return x + 1; }
// a.cpp
#include "header.hpp"
// b.cpp
#include "header.hpp"
If f was not marked inline, linking a.cpp and b.cpp together would find a conflicting method f, and compilation would fail. `inline` lets the compiler ignore this, and it simply picks one of the multiple definitions as the 'real' one and moves on with the compilation.'inline' in C is a hint to the compiler that you'd like the function inlined.
You can combine the two, and, in fact, it seems like a good idea IME to also use static if you're using inline.
Are you sure c++ is that different?
`inline` is used extensively in C++ to make header-only libraries possible; otherwise you'd get constant symbol clashes during linking. With `static` you would get enormous size blowup. It has little to do with the actual inlining of the call, which is mostly up to the compiler.
In C, the situation is complicated. `inline` does not exist in C89. GCC has an interpretation of it for C89 (-std=gnu89), which differs from the C99 interpretation. The only safe way to use inline in C is usually to couple it with `static`, unless you know what you're doing. The C99 interpretation of inline is similar to C++, but once again not exactly. For example:
// header.h
// int f(int x);
inline int f(int x) { return x + 1; }
// a.h
int a(int x);
// a.c
#include "header.h"
#include "a.h"
int a(int x) { return f(x); }
// b.h
int b(int x);
// b.c
#include "header.h"
#include "b.h"
int b(int x) { return f(x); }
// main.c
#include "a.h"
#include "b.h"
int main(int argc, char **argv) {
return a(argc) + b(argc);
}
This is code that compiles perfectly fine in C++, but is invalid C, because when the compiler decides not to inline the calls to f, it has no linkage of its own. But when one declares f to have linkage (by uncommenting that line in header.h), we now get 'multiple definition' errors.It sounds like you've confirmed my intuition about inline in C, and I find inline to be only marginally-useful at best. inline functions are syntactically-prettier than macros, but they lose the other major benefit of macros, which is increased flexibility about typing and being able to interact with syntax in ways that functions can't. I get the impression that inline probably didn't need to be included in the standard, or, at least, somehow they blew the opportunity to add something more useful.
C's situation still seems less complicated than C++'s. I can't grasp exactly what C++ 'inline' actually tells the compiler to do, based on your description. It sounds like 'inline' in C++ is just a smarter 'static'. Why can't those smarts be implanted into 'static'?
Note that you don't necessarily have to type `inline` to have inline functions. Methods defined in the declaration of a class are implicitly inline; so are template functions (but not explicit specializations).
The reason it's called `inline` instead of something else probably has something to do with the committee's aversion to new keywords, and commitment to backwards compatibility. Changing `static` would probably break a lot of code: think what would happen to static variables inside static functions.
I see no connection to the word inline in the C++ meaning. In C, at least, inline means inline.
My guess is that the C++ inline got its meaning from the winding path of c++ history, and only makes sense in the context of that history.
And whether or not the compiler inlines the code, applications will still have to be recompiled whenever there's a code change in the library.
Side note: C++ is fantastic in this regard because it makes you suffer every time for excessive coupling. The compile/link times act as a recognizable metric that devs have an interest in minimizing, and the process of doing so produces better code. I love that it is ruthless in punishing poor design.
Even then you will be rebuilding and redeploying the edge of your architecture every time this library gets a minor minor version number bump.
I would choose not to have to do that, every time.
1. It is an error to couple this library closely enough to the rest of a project's code to cause the condition you note to exist. This kind of library is best used in a small project or as part of the implementation of a user-defined abstraction interface (an abstraction specific to his project's use cases that would not make sense being included in the library code). A small project will compile quickly anyway, and the second kind of project will only need to be compiled if the abstraction's interface changes.
2. C++ compile times aren't that bad. I won't argue that it's not bad in large code bases: it indeed becomes atrocious when the codebase becomes large and spread out over a large number of compilation units (or when coupling is excessive).
Any compilation unit (source file/module) which calls a function in this library will have to be recompiled if any of the called functions change which means that your application will also have to be re-linked. There's just no way of getting around that.
To check whether handler is valid with given URL at compile time, `url' (string literal) argument requires in compile time and in run time. const char* value is invalid for template argument and argument of non-constexpr function cannot be constexpr value. Thus I used macro to provied `url' argument twice; in template argument through constexpr function and in argument.
You might be interested in metaparse [1] which can greatly simplify compile time parsing of strings but has a very steep learning curve.
Useful strings at compile time is a desirable feature beyond c++, though. A perfect hash could be a nice solution, I thought, but I got around to trying out gperf, and it was much slower than I expected. Probably too slow to use in ordinary situations. I guess gperf is for when (runtime) performance is incredibly important.
Another possible approach to strings at compile time is something like flex, or re2c. I haven't tested them in this type of scenario. But, apparently Zed Shaw used ragel to parse http in Mongrel to excellent effect. My problem with ragel is its complicated syntax.
crow::black_magic::is_equ_p(...)
I haven't yet tried the framework, but I already like you.