Outils pour utilisateurs

Outils du site


lang:cpp:preprocesseur

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
lang/cpp/preprocesseur.txt · Dernière modification : 2022/08/18 10:31 de root