En C++ 20, le préprocesseur prend en charge __VA_OPT__
comme moyen de développer éventuellement des jetons dans une macro variadique si le nombre d'arguments est supérieur à zéro. (Cela évite d'avoir à utiliser le ##__VA_ARGS__
Extension GCC, qui est un hack non portable et moche.)
Clang SVN a implémenté cette fonctionnalité, mais ils n'ont pas ajouté de macro de test de fonctionnalité pour cela. Tout pirate intelligent de préprocesseur peut-il trouver un moyen de détecter la présence ou l'absence de __VA_OPT__
support sans provoquer d'erreur matérielle ou d'avertissement de portabilité?
Inspiré par réponse de chris .
#define PP_THIRD_ARG(a,b,c,...) c
#define VA_OPT_SUPPORTED_I(...) PP_THIRD_ARG(__VA_OPT__(,),true,false,)
#define VA_OPT_SUPPORTED VA_OPT_SUPPORTED_I(?)
Si __VA_OPT__
Est pris en charge, VA_OPT_SUPPORTED_I(?)
se développe en PP_THIRD_ARG(,,true,false,)
, donc le troisième argument est true
; sinon, VA_OPT_SUPPORTED_I(?)
se développe en PP_THIRD_ARG(__VA_OPT__(,),true,false,)
, le troisième argument est false
.
Quelque chose comme ce qui suit devrait fonctionner, bien que vous puissiez l'améliorer:
#include <boost/preprocessor.hpp>
#define VA_OPT_SUPPORTED_II_1(_) 0
#define VA_OPT_SUPPORTED_II_2(_1, _2) 1
#define VA_OPT_SUPPORTED_I(...) BOOST_PP_OVERLOAD(VA_OPT_SUPPORTED_II_, __VA_OPT__(,))(__VA_OPT__(,))
#define VA_OPT_SUPPORTED VA_OPT_SUPPORTED_I(?)
Sur le tronc Clang, cela correspond à 1 en mode C++ 2a et à 0 en mode C++ 17. Le tronc GCC évalue réellement cela à 1 en C++ 17, mais gère également __VA_OPT__
Dans ce mode.
Cela permet d'utiliser BOOST_PP_OVERLOAD
Pour appeler la version _1
Ou _2
De _II
En fonction du nombre d'arguments. Si __VA_OPT__(,)
se développe en ,
, Il y aura 2 arguments vides. Sinon, il y aura 1 argument vide. Nous appelons toujours cette macro avec une liste d'arguments, donc tout compilateur prenant en charge __VA_OPT__
Doit toujours l'étendre à ,
.
Naturellement, la dépendance Boost.PP n'est pas obligatoire. Une macro simple 1 ou 2 arguments OVERLOAD
devrait être assez facile à remplacer. Perdre un peu de généralité pour le rendre plus simple:
#define OVERLOAD2_I(_1, _2, NAME, ...) NAME
#define OVERLOAD2(NAME1, NAME2, ...) OVERLOAD2_I(__VA_ARGS__, NAME2, NAME1)
#define VA_OPT_SUPPORTED_I(...) OVERLOAD2(VA_OPT_SUPPORTED_II_1, VA_OPT_SUPPORTED_II_2, __VA_OPT__(,))(__VA_OPT__(,))
Il y a un avertissement de portabilité de Clang:
avertissement: les macros variadiques sont incompatibles avec C++ 98 [-Wc ++ 98-compat-pedantic]
Je ne sais pas si cette détection est même possible sans le support des macros variadiques C++ 11. Vous pouvez envisager de ne pas prendre en charge les valeurs __cplusplus
Inférieures à C++ 11, mais Clang donne toujours l'avertissement même lorsqu'il est encapsulé dans une telle vérification.
Comme mentionné dans l'autre réponse, vous pouvez écrire votre propre macro OVERLOAD
. BOOST_PP_OVERLOAD
se compose de deux parties, BOOST_PP_CAT
et BOOST_PP_VARIADIC_SIZE
. Cependant, contrairement à Boost, vous ne vous souciez que de 2 arguments. Donc:
#define OVERLOAD(prefix, ...) CAT(prefix, VARIADIC(__VA_ARGS__))
CAT
ressemblera à:
#define CAT(a, b) KITTY((a, b))
#define KITTY(par) MEOW ## par
#define MEOW(a, b) a ## b
Et VARIADIC
:
#define VARIADIC(...) _VARIADIC_(__VA_ARGS__, 2, 1,)
#define _VARIADIC_(e0, e1, size, ...) size