Voici une autre mise en œuvre alternative. https://stackoverflow.com/a/6174263/1190123 est probablement meilleure, mais même après avoir travaillé manuellement sur quelques incréments sur papier, je ne comprends toujours pas bien les calculs/filtrages.
Elle utilise la récursion de la fonction constexpr pour compter le nombre d'éléments non déclarés dans le modèle. Highest
fonctions. __COUNTER__
est utilisé comme un mécanisme générationnel pour empêcher les nouvelles déclarations de Highest
de faire de l'auto-récurrence.
Cela ne compile que sur clang pour moi (3.3). Je ne suis pas sûr qu'il soit conforme, mais j'ai bon espoir. g++ 4.8 échoue à cause d'une fonctionnalité non implémentée (selon l'erreur). Le compilateur Intel 13 échoue également, à cause d'un bogue constexpr.
Compteur de 256 niveaux
Le nombre maximum par compteur est de 250 (CounterLimit). CounterLimit peut être augmenté jusqu'à 256 sauf si vous implémentez le truc LCount ci-dessous.
Mise en œuvre
#include <iostream>
#include <type_traits>
constexpr unsigned int CounterLimit = 250;
template <unsigned int ValueArg> struct TemplateInt { constexpr static unsigned int Value = ValueArg; };
template <unsigned int GetID, typename, typename TagID>
constexpr unsigned int Highest(TagID, TemplateInt<0>)
{
return 0;
}
template <unsigned int GetID, typename, typename TagID, unsigned int Index>
constexpr unsigned int Highest(TagID, TemplateInt<Index>)
{
return Highest<GetID, void>(TagID(), TemplateInt<Index - 1>());
}
#define GetCount(...) \
Highest<__COUNTER__, void>(__VA_ARGS__(), TemplateInt<CounterLimit>())
#define IncrementCount(TagID) \
template <unsigned int GetID, typename = typename std::enable_if<(GetID > __COUNTER__ + 1)>::type> \
constexpr unsigned int Highest( \
TagID, \
TemplateInt<GetCount(TagID) + 1> Value) \
{ \
return decltype(Value)::Value; \
}
Essais
struct Counter1 {};
struct Counter2 {};
constexpr unsigned int Read0 = GetCount(Counter1);
constexpr unsigned int Read1 = GetCount(Counter1);
IncrementCount(Counter1);
constexpr unsigned int Read2 = GetCount(Counter1);
IncrementCount(Counter1);
constexpr unsigned int Read3 = GetCount(Counter1);
IncrementCount(Counter1);
constexpr unsigned int Read4 = GetCount(Counter1);
IncrementCount(Counter1);
IncrementCount(Counter2);
constexpr unsigned int Read5 = GetCount(Counter1);
constexpr unsigned int Read6 = GetCount(Counter2);
int main(int, char**)
{
std::cout << "Ending state 0: " << Highest<__COUNTER__, void>(Counter1(), TemplateInt<0>()) << std::endl;
std::cout << "Ending state 1: " << Highest<__COUNTER__, void>(Counter1(), TemplateInt<1>()) << std::endl;
std::cout << "Ending state 2: " << Highest<__COUNTER__, void>(Counter1(), TemplateInt<2>()) << std::endl;
std::cout << "Ending state 3: " << Highest<__COUNTER__, void>(Counter1(), TemplateInt<3>()) << std::endl;
std::cout << "Ending state 4: " << Highest<__COUNTER__, void>(Counter1(), TemplateInt<4>()) << std::endl;
std::cout << "Ending state 5: " << Highest<__COUNTER__, void>(Counter1(), TemplateInt<5>()) << std::endl;
std::cout << Read0 << std::endl;
std::cout << Read1 << std::endl;
std::cout << Read2 << std::endl;
std::cout << Read3 << std::endl;
std::cout << Read4 << std::endl;
std::cout << Read5 << std::endl;
std::cout << Read6 << std::endl;
return 0;
}
Sortie
Ending state 0: 0
Ending state 1: 1
Ending state 2: 2
Ending state 3: 3
Ending state 4: 4
Ending state 5: 4
0
0
1
2
3
4
1
Compteur de niveau 250 * 250
Si vous voulez des valeurs supérieures à 256, je pense que vous pouvez combiner les compteurs. J'ai fait 250 * 250 (bien que je n'ai pas vraiment testé le comptage au-delà de 2). CounterLimit doit être abaissé à environ 250 pour les limites de récursion du compilateur. Juste pour noter, cela a pris beaucoup plus de temps à compiler pour moi.
Mise en œuvre
template <typename, unsigned int> struct ExtraCounter { };
template <unsigned int GetID, typename, typename TagID>
constexpr unsigned int LHighest(TagID)
{
return Highest<GetID, void>(ExtraCounter<TagID, CounterLimit>(), TemplateInt<CounterLimit>()) * CounterLimit +
Highest<GetID, void>(
ExtraCounter<TagID, Highest<GetID, void>(ExtraCounter<TagID , CounterLimit>(), TemplateInt<CounterLimit>())>(),
TemplateInt<CounterLimit>());
}
#define GetLCount(TagID) \
LHighest<__COUNTER__, void>(TagID())
#define LIncrementTag_(TagID) \
typename std::conditional< \
GetCount(ExtraCounter<TagID, GetCount(ExtraCounter<TagID, CounterLimit>)>) == CounterLimit - 1, \
ExtraCounter<TagID, CounterLimit>, \
ExtraCounter<TagID, GetCount(ExtraCounter<TagID, CounterLimit>)>>::type
#define IncrementLCount(TagID) \
template <unsigned int GetID, typename = typename std::enable_if<(GetID > __COUNTER__ + 7)>::type> \
constexpr unsigned int Highest( \
LIncrementTag_(TagID), \
TemplateInt<GetCount(LIncrementTag_(TagID)) + 1> Value) \
{ \
return decltype(Value)::Value; \
}
Essais
struct Counter3 {};
constexpr unsigned int Read7 = GetLCount(Counter3);
IncrementLCount(Counter3);
constexpr unsigned int Read8 = GetLCount(Counter3);
0 votes
Pouvez-vous donner un court exemple pour démontrer quelle est la question exacte ?
0 votes
N'est-il pas possible d'utiliser
X<__LINE__>
? qui fournira un numéro unique (qui peut ne pas être un numéro de série) toujours dans le fichier donné.0 votes
@iammilind : Cela ne fonctionne pas sur plusieurs en-têtes, et ne renvoie pas le même résultat de manière répétée lorsque l'unicité est atteinte. n'est pas souhaité. La solution du modèle est plus puissante. Voir la réponse.
0 votes
En rapport : C++ qui se comporte comme le COMPTEUR macro .