Comme le titre l'indique, je veux que foo
n'accepte que le type int
car c'est le deuxième paramètre.
foo(1, "TTT");
Cela fonctionne mais g ++ (version 10.2.0) génère cet avertissement
template <typename U, typename T> concept IS_INT = requires (U u, T t) { std::same_as<T, int>; };
Autre façon d'écrire IS_INT {U, T}
? se débarrasser de cet avertissement?
Enfin, comment réécrire cette contrainte (t est int) sans avoir à ajouter 0?
{ t + 0 } -> std::same_as<int>;
MODIFIER :
test.cpp:11:8: warning: template-introductions are not part of C++20 concepts [-fconcepts-ts] 11 | IS_INT {U, T} | ~~~~~~~^~~~~~
Ne donne pas d'erreur de compilation pour
#include <iostream> #include <concepts> #include <type_traits> template <typename U, typename T> concept IS_INT = requires (U u, T t) { { t + 0 } -> std::same_as<int>; }; IS_INT {U, T} void foo (U u, T t) { std::cout << "IS INT!" << std::endl; return; } int main() { foo(1, 1); return 0; }
3 Réponses :
Vous pouvez conserver la forme binaire même dans la version actuelle des concepts de base:
template<class T, class U> concept is_int = std::same_as<T, int>;
(notez l'ordre inversé des paramètres: en règle générale, si un concept accepte plusieurs paramètres, seul le premier est spécial et U vient en premier dans votre définition). Le sucre TS complet, comme l'avertit g ++, n'est actuellement pas standard.
Enfin, comment réécrire cette contrainte (t est int) sans avoir à ajouter 0?
template <typename U, typename T> concept IS_INT = requires (U u, T t) { { t + 0 } -> std::same_as<int>; }; template<class T, IS_INT<T> U> void foo (U u, T t) { std::cout << "IS INT!" << std::endl; return; }
?
Oh, en changeant { t + 0 } -> std::same_as<int>;
à std::same_as<T, int>;
ce simple ... et template<class T, IS_INT<T> U>
est ce dont j'avais besoin. Merci!
Je viens de le remarquer en changeant { t + 0 } -> std::same_as<int>;
à std::same_as<T, int>;
ne donnera pas d'erreur pour foo(1, "TTT")
alors que { t + 0 } -> std::same_as<int>;
Est-ce que. Est-ce que je manque quelque chose?
@TonyTannous oui. L'une est une exigence imbriquée qui doit être satisfaite, l'autre n'est qu'une expression unique qui compile dans tous les cas et ne contraint vraiment rien.
Pourquoi le code est-il trop compliqué pour son objectif? Le code, dans sa forme la plus simple, ressemblerait à:
#include <iostream> #include <concepts> #include <type_traits> template <typename U, typename T> concept IS_INT = std::is_integral<T>::value; IS_INT {U, T} void foo (U u, T t) { std::cout << "IS INT!" << std::endl; return; } int main() { foo(1, 1); //foo(1,1.0) // Wouldn't work for T as double - just as expected. return 0; }
La raison pour laquelle les «concepts de contrainte» ont été introduits dans C ++ 20 est de supprimer l'encombrement que SFINAE imposerait autrement. Pour supprimer l'avertissement, ajoutez simplement l' -fconcepts-ts
.
Ce n'est pas une syntaxe C ++ 20 valide.
Il a supprimé l'encombrement du code d'origine plutôt que d'avoir à promouvoir en int avec l'opérateur +. Bien que ne spécialisant pas les paramètres du modèle, la réponse s'aligne davantage sur le code d'origine - et donc ma réponse comme ci-dessus. Cependant, je comprends que la question est étiquetée c ++ 20
Comme le titre l'indique, je veux que foo n'accepte que le type
int
comme deuxième paramètre.Cela demande un concept unaire - vous voulez contraindre le 2ème paramètre, par lui-même, à être
int
. Il s'agit de vérifier une exigence d'un seul type.Ce:
{ t + 0 } -> std::same_as<int>;est un concept binaire (indépendamment de ce qui suit le
=
). Cela contraint deux types différents,T
etU
, d'une certaine manière. Peu importe ce que vous écrivez après cela, cela ne répond pas réellement à votre cas d'utilisation.Ce que vous voulez dire, c'est qu'un type est un
int
. C'est:template <typename U, std::same_as<int> T> void foo (U u, T t);Que vous pouvez utiliser, ainsi:
template <typename U, is_int T> void foo (U u, T t);Cela n'a aucune contrainte sur le premier paramètre et le deuxième paramètre doit être de type
int
.Maintenant, la bibliothèque standard est livrée avec un concept pour exactement ce problème. Il s'appelle
same_as
:template <typename T> concept is_int = std::is_same_v<T, int>;En outre, il convient de noter l'exigence:
template <typename U, typename T> concept IS_INT =N'exige pas en fait que
t
ait le typeint
. Cela vaut également pour tout type entier inférieur àint
, en raison de la promotion d'entiers.
Merci pour la réponse (déjà +1) Je suppose que je ne sais pas quand utiliser le requiert et imposer des contraintes dans le bloc {}
. Merci encore.
IS_INT {U, T}
Quelle est cette syntaxe?{ t + 0 }
Vous voulez que le type promu soitint
, ou le typeint
?@KamilCuk en.cppreference.com/w/cpp/experimental/constraints
Ensuite, vous voulez que
std::same_as<T, int>
, past + 0
soitint
.+
opérateur fera la promotion de ses opérandes.@KamilCuk oui, mais si je change le corps
{ t + 0 } -> std::same_as<int>;
àstd::same_as<T, int>;
dans main pourfoo(1, "TTT")
je n'obtiens pas d'erreur de compilation. Je suppose que j'utilise mal les concepts ...