From 2beb42a44190097c1f664c50cb27c4c73ae97eaa Mon Sep 17 00:00:00 2001 From: IncludeGuardian Date: Fri, 21 Apr 2023 23:41:08 +0100 Subject: [PATCH] Recommend `#pragma once` for self-iteration Compilers implement the "multiple-include optimization" for included files when they can detect that subsequent includes will have no effect. With Clang, GCC, and Microsoft Visual Studio this will occur when encountering a `#pragma once`, or when there is a **top-level** include guard. The idiom of self-inclusion with Boost Preprocessor requires that the include guard is nested within the `#if !BOOST_PP_IS_ITERATING` and therefore does not meet the strict criteria for the previously mentioned build optimization. The documentation has been updated to suggest `#pragma once` after all self-includes have occurred. This will allow the compiler to avoid any subsequent includes for the current translation unit and avoid extra work for the preprocessor. --- doc/topics/file_iteration.html | 37 ++++++++++++++++++++++++++++++++++ test/iteration.h | 6 ++++++ 2 files changed, 43 insertions(+) diff --git a/doc/topics/file_iteration.html b/doc/topics/file_iteration.html index 7bf70a16f..6f381b469 100644 --- a/doc/topics/file_iteration.html +++ b/doc/topics/file_iteration.html @@ -197,6 +197,7 @@

#ifndef SAMPLE_H #define SAMPLE_H + #include <boost/config.hpp> // BOOST_HAS_PRAGMA_ONCE #include <boost/preprocessor/iteration/iterate.hpp> template<int> struct sample; @@ -204,6 +205,10 @@

#define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 5, "sample.h")) ??=include BOOST_PP_ITERATE() + #ifndef BOOST_HAS_PRAGMA_ONCE + #pragma once + #endif + #endif // SAMPLE_H #else @@ -213,6 +218,17 @@

#endif +
+ Although not necessary for correctness, #pragma once is + added after BOOST_PP_ITERATE to trigger the multiple-include + optimization, allowing compilers to avoid subsequent includes of + "sample.h" to improve build speed. In this instance the the include guard + is not sufficient to trigger the multiple-include optimization as is it not + the first preprocessor directive occurring in the file. + #pragma once must occur after the last top-level + BOOST_PP_ITERATE(), after which "sample.h" will no longer + self-include. +
Using the same file like this raises another issue.  What happens when a file performs two separate file iterations over itself?  This is the @@ -227,6 +243,7 @@

#ifndef SAMPLE_H #define SAMPLE_H + #include <boost/config.hpp> // BOOST_HAS_PRAGMA_ONCE #include <boost/preprocessor/iteration/iterate.hpp> #include <boost/preprocessor/repetition/enum_params.hpp> #include <boost/preprocessor/repetition/enum_shifted_params.hpp> @@ -257,6 +274,10 @@

#define BOOST_PP_ITERATION_PARAMS_1 (4, (2, TYPELIST_MAX, "sample.h", 2)) ??=include BOOST_PP_ITERATE() + #ifndef BOOST_HAS_PRAGMA_ONCE + #pragma once + #endif + #endif // SAMPLE_H #elif BOOST_PP_ITERATION_FLAGS() == 1 @@ -331,6 +352,10 @@

#define BOOST_PP_ITERATION_PARAMS_1 (3, (1, EXTRACT_MAX, "extract.h")) ??=include BOOST_PP_ITERATE() + #ifndef BOOST_HAS_PRAGMA_ONCE + #pragma once + #endif + #endif // EXTRACT_H #else @@ -460,6 +485,10 @@

#define BOOST_PP_ITERATION_PARAMS_1 (3, (1, 2, "file.h")) ??=include BOOST_PP_ITERATE() + #ifndef BOOST_HAS_PRAGMA_ONCE + #pragma once + #endif + #endif // FILE_H #elif BOOST_PP_ITERATION_DEPTH() == 1 @@ -666,6 +695,10 @@

??=include BOOST_PP_ITERATE() + #ifndef BOOST_HAS_PRAGMA_ONCE + #pragma once + #endif + #endif // FILE_H #else @@ -938,6 +971,10 @@

??=include BOOST_PP_INCLUDE_SELF() #endif + #ifndef BOOST_HAS_PRAGMA_ONCE + #pragma once + #endif + // iteration over cv-qualifiers #elif BOOST_PP_ITERATION_DEPTH() == 1 \ && BOOST_PP_ITERATION_FLAGS() == 1 \ diff --git a/test/iteration.h b/test/iteration.h index 035531aa7..b05de82f5 100644 --- a/test/iteration.h +++ b/test/iteration.h @@ -11,6 +11,8 @@ # # if !BOOST_PP_IS_ITERATING # +# include +# # include # include # include @@ -177,6 +179,10 @@ # # undef ITER50SA # +# ifndef BOOST_HAS_PRAGMA_ONCE +# pragma once +# endif +# # endif # # else