Puis-je empêcher la génération d'une fonction d'une classe basée sur un modèle si les arguments du modèle ne répondent pas à un critère (certaine valeur ou type)? Cela peut-il être réalisé en utilisant du code C ++ et aucune directive de préprocesseur?
Ce type de fonction ne doit être disponible ni dans l'en-tête ni dans le corps. Ce cas peut sembler un peu artificiel mais je n'ai pas encore trouvé de solution.
Exemple de classe (simplifié - pas de constructeur etc.):
MyClass.h strong >
int main() { auto myclass0 = MyClass<2>(); myclass0.DoSomething(); // OK myclass0.DoAnotherThing(); // (wanted) error - function not available auto myclass1 = MyClass<3>(); myclass1.DoSomething(); // OK myclass1.DoAnotherThing(); // OK }
MyClass.cxx
template< int Dimension, typename TPixelType> void MyClass::DoSomething() {...} // pseudocode: if Dimension <= 2 do not compile next function template< int Dimension, typename TPixelType> void MyClass::DoAnotherThing() { MethodNotToBeCompiled(); // The function I don't want to be executed }
TestMyClass.cxx strong >
template<int Dimension, typename TPixelType = float> class MyClass { void DoSomething(); void DoAnotherThing(); // this function should only be available if Dimension > 2 }
Est-ce possible en C ++ XX? Ou existe-t-il une autre approche que les directives de préprocesseur?
3 Réponses :
template <int Dimension, typename TPixelType> void MyClass::DoSomething() {/*...*/} // if Dimension <= 2 do not compile next function template <int Dimension, typename TPixelType> void MyClass::DoAnotherThing() { static_assert(Dimension > 2, "function not available!" ); // ... }
Comment gérer le code après static_assert ()
? Il semble que static_assert affecte tout le processus de compilation. Je veux juste une fonction sinlge qui ne compile pas.
Que voulez-vous dire? lorsque vous utilisez cette fonction avec un paramètre invalide ( <= 2
) le compilateur ne vous permet pas de le faire et vous donne une erreur fonction non disponible!
. Le code après static_assert ()
devrait être comme le code normal, il n'y a pas de différence. Dans l'exemple après static_assert (...);
vous pouvez mettre: int i = Dimension * 3;
L'assertion empêche-t-elle la compilation de cette méthode ou simplement l'exécution? J'essaie de comprendre à quel point le static_assert
déploie ses fonctionnalités.
@KabCode static_assert
vous donne l'erreur de compilation, donc il empêche la compilation.
En C ++ 2a, vous pouvez utiliser la méthode requires
pour "supprimer":
template<int Dimension, typename TPixelType = float> class MyClass { void DoSomething(); void DoAnotherThing() requires (Dimension > 2); };
Jusqu'où est l'implémentation de C ++ 2a? Peut-il être déjà utilisé (avec le compilateur visuel)?
Vous pouvez consulter les documents. microsoft.com/en-us/cpp/overview/… . Donc actuellement pas encore pris en charge dans le visuel (gcc prend en charge nécessite
).
Ce serait ma réponse préférée si je pouvais utiliser requires
.
@ Jarod42 est trop en avance sur son temps :-) solution sympa néanmoins, heureux de l'avoir essayé a >!
Suggestion générale: si vous avez une classe de modèle, implémentez tout dans l'en-tête et évitez les fichiers cpp. Tout devient beaucoup plus simple.
Puis-je empêcher la génération d'une fonction d'une classe basée sur un modèle si les arguments du modèle ne répondent pas à un critère (certaine valeur ou type)? Cela peut-il être réalisé en utilisant du code C ++ et aucune directive de préprocesseur?
Oui et oui: recherchez SFINAE.
Dans votre cas (C ++ 11 et plus récent)
auto myclass0 = MyClass<2>(); myclass0.DoAnotherThing<5>(); // doesn't compile anymore because 5 != 2
Maintenant, le La méthode DoAnotherThing ()
est implémentée uniquement lorsque D> 2
où D
, par défaut est égal à Dimension
.
N'est pas une solution parfaite car peut être "détourné" expliquant la valeur de D
template <int D = Dimension, // ..VVVVVVVVVVVVVVVV typename std::enable_if<(D == Dimension) && (D > 2), bool>::type = true> void DoAnotherThing() { }
mais vous pouvez éviter cela problème en ajoutant le test que D
est égal à Dimension
auto myclass0 = MyClass<2>(); myclass0.DoAnotherThing<5>(); // compile because D is 5
so
template <int Dimension, typename TPixelType = float> class MyClass { public: void DoSomething () { } template <int D = Dimension, typename std::enable_if<(D > 2), bool>::type = true> void DoAnotherThing() { } };
Cela peut être combiné avec if constexpr () {}
pour éviter que l'appel de fonction ne génère des erreurs de compilation.
pas la question mais pertinente: stackoverflow.com/questions/495021/...
par curiosité: comment utiliseriez-vous le préprocesseur? Je ne sais pas comment cela pourrait être fait avec le préprocesseur
Vous pouvez spécialiser les modèles, c'est donc conceptuellement trivial. Comment écrire du «bon» code pour les grandes classes de modèles avec des spécialisations est une autre question (l'héritage peut aider). Mais peut-être que SFINAE est également suffisant dans votre cas.
static_assert (2