1
votes

polymorphisme statique c ++ (CRTP) résultant en un type incomplet lors de l'évaluation d'une `static constexpr`

J'ai besoin d'accéder à un static constexpr et une solution que j'ai mise en place fonctionne avec gcc ( live exemple ) mais pas avec vc ++ ( exemple en direct ).

Le code est le suivant:

template<class Drvd>
class Base
{
public:
    static constexpr bool val = Drvd::val;
};

class Derived : public Base<Derived>
{
    friend class Base;
private:
    static constexpr bool val = true;
};

int main()
{
    std::cout << Derived::Base::val << std::endl;
}

C'est donc un bogue avec vc ++, mais n'importe qui a une idée sur la façon d'atteindre le val défini dans Base comme valeur de val dans Drvd d'une manière différente dont vc ++ ne se plaindra pas?

Modifier: Notez que le résultat est le même avec la variante: friend class Base ; au lieu de friend class Base;


3 Réponses :


1
votes

Vous pouvez utiliser une méthode:

#include <iostream>

template<class Drvd>
class Base
{
public:
    static constexpr bool val() { return Drvd::val;  }
};

class Derived : public Base<Derived>
{
    friend class Base<Derived>;
private:
    static constexpr bool val = true;
};

int main()
{
    std::cout << Derived::Base::val() << std::endl;
}

exemple en direct: https: // rextester .com / IHR24393


2 commentaires

Belle variante, mais je devrais recourir à l'ajout de () . Si rien d'autre, je suppose que cela devrait faire. Merci.


Un autre commentaire, utilisant une fonction constexpr , tout en travaillant pour ce cas particulier, est également limitant de pouvoir utiliser val () comme paramètre de modèle.



1
votes

votre problème ne concerne pas les déclarations private / friend (le code ne se compilerait pas même si "val" était un public), votre problème est que lors de l'instanciation de

static constexpr bool val = Drvd::val

Drvd est encore de type incomplet. Voir ci-dessous la question / réponse pour savoir comment contourner ce problème avec les classes de traits.

Polymorphisme statique C ++ (CRTP) et utilisation de typedefs de classes dérivées

PS en fait, je viens de signaler votre question comme étant en double


1 commentaires

merci, cela semble être la bonne direction. Bien que je ne sois pas sûr qu'il s'agisse directement d'un doublon, je vais essayer de jouer avec les informations de l'autre page et de voir quels résultats.



0
votes

Selon @David, le problème vient du fait que Face est incomplète, car il entre dans Base avant de terminer la définition de Face .

Cependant, la solution liée par @David est un peu ancienne et manque quelques astuces dont nous pouvons profiter. À savoir, @ m.s. nous montre que les fonctions static constexpr sont très bien - et aussi basées sur ma propre expérimentation - et que nous n'avons vraiment besoin de traiter que ce cas particulier des variables static constexpr , et peut-être des types accessible depuis Derived.

Ce qui suit ( exemple en direct ) montre comment résoudre ce problème, tout en gardant chaque classe encapsulée dans son propre fichier h, ce qui le rend un peu plus propre:

#include <iostream>

// Begin: h-file of Base
template<class Drvd>
class ConstValue;

template<class Drvd>
class Base
{
public:
    static constexpr bool val = ConstValue<Drvd>::val;
};
// End: h-file of Base

// Begin: h-file of Derived
class Derived;

template<>
class ConstValue<Derived>
{
public:
    static constexpr bool val = true;
};

class Derived : public Base<Derived>
{
    friend class Base<Derived>;
private:
    static constexpr bool val = true; // optional
};
// End: h-file of Derived

// Main
int main()
{
    std::cout << Derived::Base::val << std::endl;
}

L'idée générale est que pour chaque constexpr à laquelle Base doit accéder depuis Derived , nous pouvons créer une classe unique qui encapsule les variables, puis surcharger la classe pour chaque Derived code> qui utilise Base.


0 commentaires