web-dev-qa-db-fra.com

Qu'est-ce qui est autorisé dans une fonction constexpr?

les fonctions constexpr ne sont pas censées contenir:

Une définition d'une variable de type non littéral

Mais dans cette réponse, un lambda est défini en un seul: https://stackoverflow.com/a/41616651/2642059

template <typename T>
constexpr auto make_div(const T quot, const T rem)
{
    return [&]() {
        decltype(std::div(quot, rem)) result;
        result.quot = quot;
        result.rem = rem;
        return result;
    }();
}

et dans mon commentaire je définis un div_t en un: Comment puis-je initialiser un objet div_t?

template <typename T>
constexpr decltype(div(T{}, T{})) make_div(const T quot, const T rem)
{
    decltype(div(T{}, T{})) x{};
    x.quot = quot;
    x.rem = rem;
    return x;
}

Qu'entend-on exactement par l'interdiction de la "définition d'une variable de type non littéral"?

Visual Studio 2015 ne permettra pas ma définition d'un div_t mais je trouve absurde qu'il soit permis d'envelopper un tel comportement illégitime dans un lambda et de l'exécuter. Je voudrais savoir lequel si l'un des compilateurs se comporte correctement par rapport au div_t définition.

17
Jonathan Mee

Il est pratiquement garanti que s'il y a une anomalie, gcc a le comportement correct, car Visual Studio 2015 ne prend pas en charge c ++ 14 l'extension de constexpr: https: //msdn.Microsoft.com/en-us/library/hh567368.aspx#C-14-Core-Language-Features

Fonctions C++ 11 constexpr

Le corps de la fonction peut uniquement contenir:

  • instructions null (points-virgules simples)
  • static_assert Déclarations
  • typedef déclarations et déclarations d'alias qui ne définissent pas de classes ou d'énumérations
  • using déclarations
  • using directives
  • exactement une instruction return

Donc c ++ 11 ne peut pas tolérer la définition de decltype(div(T{}, T{})) x{}. Il serait cependant acceptable de rouler le ternaire suggéré ici dans une fonction constexpr pour obtenir les mêmes résultats:

template <typename T>
constexpr auto make_div(const T quot, const T rem)
{
    using foo = decltype(div(T{}, T{}));

    return foo{1, 0}.quot != 0 ? foo{quot, rem} : foo{rem, quot};
}

Live Example

Fonctions C++ 14 constexpr

Le corps de la fonction peut contenir autre chose que :

  • une déclaration asm
  • une déclaration goto
  • une instruction avec une étiquette autre que case et default
  • un bloc d'essai
  • une définition d'une variable de type non littéral
  • une définition d'une variable de durée de stockage statique ou de thread
  • une définition d'une variable pour laquelle aucune initialisation n'est effectuée

Lorsqu'un "type littéral" est défini ici , spécifiquement pour les objets cependant, ils peuvent être des types agrégés avec un destructeur trivial. Donc div_t Est définitivement admissible. Ainsi c ++ 14 , et par extension gcc, peut tolérer la définition de decltype(div(T{}, T{})) x{}.

Fonctions C++ 17 constexpr

C++ 17 a ajouté la prise en charge des types de fermeture à la définition de "Literal Type", donc je trouve étrange que gcc et Visual Studio prennent en charge l'utilisation du lambda dans l'instruction return. Je suppose que c'est soit un support prospectif, soit le compilateur a choisi d'intégrer le lambda. Dans les deux cas, je ne pense pas que cela puisse être considéré comme une fonction c ++ 14constexpr.

[ Source ]

16
Jonathan Mee