3
votes

Comment créer du code en fonction des arguments du modèle?

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?


4 commentaires

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


3 Réponses :


7
votes
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!" );
    // ...
}

4 commentaires

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.



6
votes

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);
};


4 commentaires

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é !



3
votes

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 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()
       { }
 };


1 commentaires

Cela peut être combiné avec if constexpr () {} pour éviter que l'appel de fonction ne génère des erreurs de compilation.