J'apprends des concepts et je ne peux pas trouver un moyen de restreindre la valeur (et non le type) du paramètre de modèle non type.
Exemple de code qui se compile, bien que j'aurais souhaité que ce ne soit pas le cas (en raison d'un échec d'exigence):
#include <cassert> enum Bla{ Lol, Haha }; template<Bla b> requires requires{ // my guess is that this just checks that this is valid expression, not // that it is true b>1; } void f(){ assert(b>1); } int main() { f<Lol>(); // compiles, not funny ;) }
Remarque: ceci est un exemple simplifié (je veux une "surcharge de modèle") donc static_assert
n'est pas bon pour moi, et j'essaie d'éviter std::enable_if
car la syntaxe est hideuse.
3 Réponses :
Puisque f
doit être contraint que par la valeur du paramètre de modèle non-type, vous pouvez simplement écrire une clause requires
au lieu d'une contrainte ad-hoc requires requires
:
static_assert(b>1);
Voici une démo .
Vous n'avez besoin que d'une expression requires requires
si vous souhaitez effectuer des vérifications plus compliquées sur le paramètre de modèle. Dans ce cas, je recommande quand même d'utiliser un concept nommé sur une contrainte ad hoc. Cela rend le code plus lisible et vous permet de réutiliser le concept à d'autres endroits.
Quant à l' assert
, c'est une construction au moment de l'exécution, donc cela n'affecte en rien la compilation, en supposant que l'expression à l'intérieur de l' assert
est syntaxiquement valide. Vous devez utiliser static_assert
place, si vous souhaitez vérifier le paramètre du modèle au moment de la compilation:
template<Bla b> requires (b>1) void f() {}
@ idclev463035818 a raison, affirmer est juste pour montrer que le code meurt au moment de l'exécution ... Votre solution est excellente, mais maintenant je ne comprends pas pourquoi je n'ai besoin que d'un seul :), mais oui, cela sort du cadre de cette question.
@NoSenseEtAl requires requires
une contrainte ad-hoc. Il est uniquement utilisé avec des expressions obligatoires, pas des clauses obligatoires. Ouais, ça devrait probablement être une question différente.
Vous devez faire la différence entre une clause requires et une expression requires .
// Allows any specialization over MyEnum. template<MyEnum e> struct Wrapped {}; // Overloading Wrapped specializations by // mutually exclusive constraints: template<MyEnum e> void f(Wrapped<e>) requires (e == MyEnum::Foo || e == MyEnum::Bar) { std::cout<< __PRETTY_FUNCTION__ << "\n"; } template<MyEnum e> void f(Wrapped<e>) requires (e == MyEnum::Baz) { std::cout<< __PRETTY_FUNCTION__ << "\n"; } int main() { f(Wrapped<MyEnum::Foo>{}); // void f(Wrapped<e>) requires e == MyEnum::Foo || e == MyEnum::Bar [with MyEnum e = MyEnum::Foo] f(Wrapped<MyEnum::Bar>{}); // void f(Wrapped<e>) requires e == MyEnum::Foo || e == MyEnum::Bar [with MyEnum e = MyEnum::Bar] f(Wrapped<MyEnum::Baz>{}); // void f(Wrapped<e>) requires e == MyEnum::Baz [with MyEnum e = MyEnum::Baz] }
En particulier, selon [temp.pre] / 1 , la grammaire d'une clause requires est:
enum class MyEnum { Foo, Bar, Baz }; // Allows any specialization over MyEnum. template<MyEnum e> struct Wrapped {}; // Allows only Wrapped objects of certain // specializations. template<MyEnum e> void f(Wrapped<e>) requires (e == MyEnum::Foo || e == MyEnum::Bar) { } int main() { f(Wrapped<MyEnum::Foo>{}); // OK f(Wrapped<MyEnum::Bar>{}); // OK f(Wrapped<MyEnum::Baz>{}); // Error: ... constraints not satisfied }
où contrainte-ou-expression-logique , à son tour, est une expression-primaire , qui comprend une expression-requise : s .
Dans votre cas, vous utilisez une expression requise ad-hoc (par rapport à une contrainte nommée) comme condition requise pour une clause require . Cependant, pour votre cas d'utilisation, il suffit d'utiliser une clause requires avec une expression constante . En particulier, vous pouvez restreindre la valeur d'un paramètre de modèle non-type par une expression constante dans la clause requiert de fin d'une entité modèle donnée, par exemple un modèle de fonction:
requires-clause: requires constraint-logical-or-expression
Appliqué pour la surcharge avec des contraintes mutuellement exclusives:
template<Bla b> void f() requires .... {} // ^^^^ - constant-expression OR // requires-expression // // ^^^^^^^^^^^^^ - requires-clause
Si vous n'avez qu'une condition booléenne et rien d'autre, procédez comme suit:
template<Bla b> requires requires { requires b > 1; // ^~~~~~~~ } void f() {}
Une autre syntaxe plus longue, si vous avez besoin de vérifier plus de choses dans la même, requires
-expression:
template<Bla b> requires(b > 1) void f() {}
Le commentaire le plus voté sur cette question a trouvé une réponse? : P stackoverflow.com/questions/54200988/... Accepter cela car bien que la réponse cigen soit plus tôt, vous donnez un moyen de faire des choses plus compliquées ...
Pourquoi s'arrêter à imbriquer une seule expression-obligatoire dans une autre? ;)
@dfrib Vous venez de trouver un bogue GCC avec __PRETTY_FUNCTION__
. : P
@HolyBlackCat quel bug? manque de place?
@NoSenseEtAl Oui.
static_assert
ferait échouer, mais je suppose que ce n'est qu'un exemple simplifié@ idclev463035818 Je le veux pour surcharge, donc oui.