Changes between Version 25 and Version 26 of BestPracticeHandbook
- Timestamp:
- May 19, 2015, 6:28:02 PM (7 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
BestPracticeHandbook
v25 v26 852 852 }}} 853 853 854 This works very well when (a) your policy implementations fit nicely into template types and (b) the number of policy taking template types is reasonably low (otherwise you'll be doing a lot of typing as any changes to the policy design requires modifying every single instantiation of the policy taking template types). Another problem with policy based design is that it generates a lot of template instantiations, and generating a lot of template instantiations is bad because compilers often cannot do constant time type lookups and instead have linear or worse type lookups, so instantiating tens of million types is always going to be a lot slower to compile and sometimes link than millions of types.854 This works very well when (a) your policy implementations fit nicely into template types and (b) the number of policy taking template types is reasonably low (otherwise you'll be doing a lot of typing as any changes to the policy design requires modifying every single instantiation of the policy taking template types). Another problem with policy based design is that it generates a lot of template instantiations, and generating a lot of template instantiations is bad because it is slow (type instantiation is typically linear to the number of types already instantiated and quadratic to the number of partial specialisations affecting a type, but some compilers are quadratic for both). 855 855 856 856 Consider instead doing an ADL based namespace composure design pattern which is just a different way of doing policy based design. It can be highly effective in those niches where the traditional policy taking template approach falls down. Here is the same program above written using ADL namespace composure: … … 926 926 }}} 927 927 928 The first example instantiates five types to be thence considered during global type lookup, so let's say it has cost five to future code lookups. The second example instantiates no types at all at global lookup scope, so it has cost zero to future code lookups because all the types are declared inside namespaces normally not considered during global type lookups. Thesecond example may also require less refactoring in the face of changes than the traditional form.928 The first example instantiates five types, so let's say it adds a cost of five. The second example instantiates merely the three empty tag types in each namespace, and otherwise only free functions which don't participate in global overload resolution unless ADL brings them into consideration. This ought to add much less load to the compiler than the traditional design. This second example may also require less refactoring in the face of changes than the traditional form. 929 929 930 930 The above pattern is in fact entirely C++ 03 code and uses no C++ 11. However, template aliasing in C++ 11 makes the above pattern much more flexible. Have a look at https://github.com/ptal/expected/blob/master/include/boost/functional/monads/rebindable.hpp for examples of this ADL invoked namespace composure design pattern. 931 931 932 932 933 == 15. BUILD: Consider defaulting to header only, but actively manage facilities for reducing build times == … … 940 941 3. Precompiled not header only (library implementation put into a shared library) 941 942 4. Precompiled header only with link time optimisation 943 942 944 943 945 ||= Build flags =||= Microsoft Windows 8.1 x64 with Visual Studio 2013 =||= Ubuntu 14.04 LTS Linux x64 with GCC 4.9 and gold linker =||= Ubuntu 14.04 LTS Linux x64 with clang 3.4 and gold linker =|| … … 1007 1009 }}} 1008 1010 1009 This looks a bit complicated, but isn't really. Generally you will mark up those classes and structs you implement in a .ipp file (this being the file implementing the APIs declared in the header ) with `BOOST_AFIO_DECL`, functions with `BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC`, all out-of-class member functions (i.e. those not implemented inside the class or struct declaration) with `BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC`, all virtual member functions with `BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC` and append to all unimplemented virtual member functions`BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC`. This inserts the correct markup to generate both optimal header only and optimal non header only outcomes.1011 This looks a bit complicated, but isn't really. Generally you will mark up those classes and structs you implement in a .ipp file (this being the file implementing the APIs declared in the header which is included by the header if building header only, else is included by a .cpp file if not building header only) with `BOOST_AFIO_DECL`, functions with `BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC`, all out-of-class member functions (i.e. those not implemented inside the class or struct declaration) with `BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC`, all virtual member functions with `BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC` and append to all unimplemented virtual member functions `BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC`. This inserts the correct markup to generate both optimal header only and optimal non header only outcomes. 1010 1012 1011 1013 '''2. Precompiled headers''' … … 1059 1061 The idea behind this is to tell the compiler to not instantiate common instantiations of your template types on demand for every single compiland as you will explicitly instantiate them exactly once elsewhere. This can give quite a bump to build times for template heavy libraries. 1060 1062 1063 '''4. Use C++ Modules''' 1064 1065 If you are on a very recent clang, or on a MSVC made sometime after 2016, there will probably be some implementation of C++ Modules available. C++ Modules as presently proposed for C++ 1z is poorly named in that after multiple rounds of simplification it provides little modularity at all, and is now really the beginnings of an AST database assisted build system which can dramatically improve build times in a similar way to precompiled headers. I therefore really wish that "C++ Modules" were called "C++ Build Acceleration" instead, but unfortunately no one proposing this feature to WG21 seems to agree. Anyway, for clang follow the instructions at http://clang.llvm.org/docs/Modules.html whereby you write up a module map file which delineates your header files into AST database objects, and your compiler will precompile your headers into an AST database. Unfortunately it presently seems you must manually annotate what parts are exposed and what parts are hidden in the module map rather than being able to reuse any dllimport/dllexport infrastructure already present. Your code when it includes a header will now have the compiler automatically go fetch the precompiled version from the database and use all exported types. 1066 1067 Microsoft unfortunately presently do not intend to implement Modules in the same way as clang, and requires you to do a lot more work including source code modification. Follow the instructions at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4465.pdf instead. 1068 1069 If you think of "C++ Modules" as really a somewhat more flexible and reusable implementation of existing precompiled headers which lets the compiler figure out what precompiled parts to use without you manually telling it as you must right now, you can estimate whether it is worth the effort to add support for Modules to your library as the speedup is likely similar to a precompiled header. The clang method is non-intrusive to your source code and doesn't get in the way of older compilers, but adds significant hassle in keeping the module map and the source code in sync. The Microsoft method seems to require a fair bit of #ifdef, but the module specification must be part of the source code which may aid keeping it in sync. 1070 1061 1071 1062 1072 == 16. COUPLING: Consider allowing your library users to dependency inject your dependencies on other libraries == 1073 1074 1063 1075 1064 1076 == 17. FUTURE PROOFING: Consider being C++ resumable function ready ==