Utiliser les std::initializer_list (crochets) avec des macros
Le préprocesseur, comme le compilateur considère la virgule comme séparateur d'argument. Mais seul le compilateur considère les crochets {}
comme un groupe d'argument. Le préprocesseur va considérer une virgule à l'intérieur d'un groupe de crochets comme un changement d'argument. La solution consiste à définir explicitement le type et à entourer les crochets par des parenthèses : (std::list<int>{.., .., ..})
.
- cpp/preprocessor/bracket.cpp
#define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) #include <list> namespace { void f(const std::list<int>&) {} } // namespace #define F(XXXX, ...) f(XXXX) int main() { std::list<int> c; f(c); f(std::list<int>{1, 2, 3, 4}); f({1, 2, 3, 4}); // Failed. Macro stops at first comma. STR(F(std::list<int>{1, 2, 3, 4})); // OK STR(F((std::list<int>{1, 2, 3, 4}))); // OK STR(F(std::list<int>({1, 2, 3, 4}))); // Failed. Macro stops at first comma. STR(F({1, 2, 3, 4})); // Failed. With double parentheses, c++ can't auto deduce std::list<std::string>. STR(F(({1, 2, 3, 4}))); }
Rendu :
- cpp/preprocessor/bracket.cpp.i
namespace std { typedef long unsigned int size_t; typedef long int ptrdiff_t; typedef decltype(nullptr) nullptr_t; } namespace std { inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { } } namespace __gnu_cxx {
On voit bien que le préprocesseur respecte les parenthèses mais pas les crochets.
Passing an initialization list to a macro Archive du 21/05/2015 le 27/08/2019
Remplacer les #define par #pragma once
On peut lancer le script python suivant.
Il remplace le premier #ifndef/#define
par #pragma once
et supprimer le dernier #endif
.
La méthode n'est pas parfaite. Elle peut poser des problèmes sur les fichiers n'ayant pas le mécanisme d'anti inclusion multiple.
- remove_header.py
import re from pathlib import Path def my_function(fname): with open(fname, 'r') as infile: lines = infile.readlines() pifn = re.compile('^#ifndef') pdefinc = re.compile('^#define INCLUDED_.*_H??') pendif = re.compile('^#endif') i = len(lines)-2 for i in range(len(lines)-1): if lines[i] == '#pragma once\n': return if pifn.search(lines[i]) and pdefinc.search(lines[i+1]): break if i != len(lines)-2: print(i, lines[i]) lines[i] = "#pragma once\n" del lines[i+1] for i in range(len(lines)-1, -1, -1): if pendif.search(lines[i]): print(i, lines[i]) del lines[i] if lines[i-1]=="\n" and len(lines) != i and lines[i]=="\n": del lines[i] with open(fname, 'w', newline='\n') as outfile: outfile.write(''.join(lines)) break for path in Path('G:\\Github\\libreoffice\\').rglob('*.h*'): try: my_function(path) except UnicodeDecodeError: pass except PermissionError: pass