2017-05-01 1 views
3

Supposons que j'ai une macroComment puis-je invoquer une macro avec tous les points d'un produit catersien d'ensembles d'arguments?

FOO(a, b) 

et je veux invoquer cette macro avec un certain (fixe) de valeurs possibles pour a; et un certain ensemble fixe de valeurs pour b. Ainsi, si mon ensemble de valeurs b est bar et baz et mon ensemble de valeurs b est fiz et bang, je veux:

FOO(bar, fiz) 
FOO(bar, bang) 
FOO(baz, fiz) 
FOO(baz, bang) 

séparés soit par de nouvelles lignes, soit par des points-virgules, ou les deux - c'est un problème mineur si ignorons-le; l'ordre exact des 4 invocations n'est pas non plus important.

Maintenant, si je n'avais qu'une « dimension » des paramètres, je pourrais utiliser William Swanson de mechanism (comme décrit ici sur le site, et il y a même un github repository pour elle), et écrire

MAP(SINGLE_PARAMETER_MACRO, bar, baz, quux) 

à obtenir

SINGLE_PARAMETER_MACRO(bar) 
SINGLE_PARAMETER_MACRO(baz) 
SINGLE_PARAMETER_MACRO(quux) 

mais la chose est, je deux dimensions; et il semble impossible/difficile de séparer votre __VA_ARGS__ en deux ensembles différents et de parcourir l'espace bidimensionnel des paires d'éléments de ces ensembles.

Est-ce que cela peut (raisonnablement) être fait?

Notes:

  • Je suis intéressé par une solution à base de C-préprocesseur, mais si vous avez quelque chose qui ne fonctionne que dans C++ pour une raison étrange, c'est ok aussi.
  • La solution doit être uniquement au moment de la compilation et doit être valide presque partout dans votre unité de traduction C/C++; spécifiquement, dans les définitions de classe et à la portée du fichier. Vous pouvez deviner que c'est un XY problem, et vous avez raison; mais s'il vous plaît ne choisissez pas à ma motivation puisque les deux X et Y sont à mon humble avis.
  • Si vous pouvez maintenir un ordre lexicographique des invocations de macros, ce serait bien.
+2

Je ne pense pas qu'il existe des mécanismes de bouclage dans le préprocesseur. Pourquoi ne pouvez-vous pas le faire dans une boucle d'exécution? – Barmar

+0

@Barmar: 'FOO' peut être une déclaration ou une définition, pas une déclaration. Le préprocesseur admet un mécanisme de bouclage list-head-vs-tail - mais il n'est pas intrinsèquement multidimensionnel. – einpoklum

+0

@WilliamSwanson: Peut-être en tant qu'auteur de la réponse connexe, vous pourriez avoir un conseil pour moi? – einpoklum

Répondre

1

La bibliothèque de préprocesseur d'amplification peut exécuter des produits cartésiens déjà sur des listes et des séquences de préprocesseur. Vous ne spécifiez pas les types de données préprocesseur que vous voulez entrer ... en supposant que A et B sont tuples, et que vous avez variadics, vous pouvez faire:

#include <boost/preprocessor/seq/for_each_product.hpp> 
#include <boost/preprocessor/seq/to_tuple.hpp> 
#include <boost/preprocessor/tuple/to_seq.hpp> 

#define EVAL(...) __VA_ARGS__ 
#define FOO_SEMI_DELIM(R,SEQ_X) EVAL(FOO BOOST_PP_SEQ_TO_TUPLE(SEQ_X)); 
#define FOO_CARTESIAN(TUP_A,TUP_B) \ 
    BOOST_PP_SEQ_FOR_EACH_PRODUCT \ 
    (FOO_SEMI_DELIM, \ 
    (BOOST_PP_TUPLE_TO_SEQ(TUP_A)) \ 
    (BOOST_PP_TUPLE_TO_SEQ(TUP_B)) \ 
    ) 

FOO_CARTESIAN((John,Jane),(Smith,Jones,Parker,Peterson)) 

Depuis FOO est en majuscules, je En supposant que vous voulez finir par appeler FOO comme une macro; EVAL ici vous permet de le faire.

Vous pouvez facilement l'étendre à des produits cartésiens de plus grandes dimensions.

+0

Voilà ma réponse: une forte dépendance sur le mécanisme du préprocesseur Boost, mais c'est un prix raisonnable à payer je suppose. – einpoklum

3

BOOST_REPEAT_PP peut vous aider.

Par exemple, si vous avez deux tableaux de nombres, vous pouvez le faire en C++ 14:

#include <boost/preprocessor/repetition/repeat.hpp> 
#include <array> 
#include <iostream> 

constexpr std::array<int, 2> a = {2, 4}; 
constexpr std::array<int, 3> b = {1, 3, 7}; 

#define MYNUMBER2(z, n, x) std::cout << a[x] << " " << b[n] << std::endl; 
#define MYNUMBER(z, n, x) BOOST_PP_REPEAT(3, MYNUMBER2, n) 

int main() { 
    BOOST_PP_REPEAT(2, MYNUMBER, 0); // The "0" is actually not used 
} 

Sortie:

2 1 
2 3 
2 7 
4 1 
4 3 
4 7 

Si vous ne souhaitez pas utiliser std::array , vous pouvez également suivre une approche comme celle-ci (ne nécessite pas C++ 14):

#include <boost/preprocessor/repetition/repeat.hpp> 
#include <iostream> 

#define A_0 "bar" 
#define A_1 "baz" 
#define A_2 "ban" 

#define B_0 "fiz" 
#define B_1 "bang" 

#define FOO(s1, s2) std::cout << s1 << " " << s2 << std::endl; 
#define MYSTRING2(z, n, x) FOO(A_##x, B_##n) 
#define MYSTRING(z, n, x) BOOST_PP_REPEAT(2, MYSTRING2, n) 

int main() { 
    BOOST_PP_REPEAT(3, MYSTRING, 0); // The "0" is actually not used 
} 

Sortie:

bar fiz 
bar bang 
baz fiz 
baz bang 
ban fiz 
ban bang 
+0

Est-ce que cela fonctionne à la portée du fichier, c'est-à-dire pour les définitions/déclarations? – einpoklum

+0

@einpoklum oui, il ne fait que de la macro substitution donc tout devrait être possible – oLen

+1

@einpoklum oui, vous pouvez facilement l'utiliser pour les déclarations. [Exemple] (https://wandbox.org/permlink/5iEXuuaDdbp1cdaY) – xinaiz