web-dev-qa-db-fra.com

Quel est le nom de cette fonctionnalité de modèle C ++ inhabituelle utilisée par Boost.Spirit?

Le code ci-dessous provient de la documentation Boost.Spirit x . Il utilise une syntaxe C++ intéressante que je n'ai jamais vue auparavant, qui est presque impossible à décrire dans une requête de recherche sans connaître la terminologie appropriée. Est-ce un raccourci pour la déclaration anticipée d'une classe? Où cette fonctionnalité est-elle mentionnée dans la norme C++?

namespace parser
{
    using x3::eps;
    using x3::lit;
    using x3::_val;
    using x3::_attr;
    using ascii::char_;

    auto set_zero = [&](auto& ctx){ _val(ctx) = 0; };
    auto add1000 = [&](auto& ctx){ _val(ctx) += 1000; };
    auto add = [&](auto& ctx){ _val(ctx) += _attr(ctx); };

    // What is this? This is the very first use of the identifier `roman`.
    x3::rule<class roman, unsigned> const roman = "roman";
    //       ^^^^^^^^^^^

    auto const roman_def =
        eps                 [set_zero]
        >>
        (
            -(+lit('M')     [add1000])
            >>  -hundreds   [add]
            >>  -tens       [add]
            >>  -ones       [add]
        )
    ;

    BOOST_SPIRIT_DEFINE(roman);
}
51
Barrett Adair

Les arguments d'un modèle ne doivent pas nécessairement être définis pour être utilisés. L'utilisation de "classe romaine" déclare en fait la classe romaine.

Voici un exemple de code:

#include <iostream>
template <class T> void foo();
template<> void foo<class roman>()
{
    // allowed because roman is declared
    roman* pointer1;
    // not allowed because romania is not declared
    // romania* pointer2;
    std::cout << "Hello world!" << std::endl;
    return;
}
int main(int argc, char** argv) {
    return 0;
}

Comme les gens l'ont souligné dans les commentaires ci-dessus, cela distingue cette instanciation du modèle. Et pour répondre directement à la question que vous vous posiez, la spécification de la nature de l'argument de modèle dans une instanciation de modèle est appelée "spécificateur de type élaboré".

41
Robert Prévost

C'est la même chose que:

class roman;

x3::rule<roman, unsigned> const roman = "roman";

En d'autres termes, écrire class T où un nom de type est attendu, déclare d'abord que T est le nom d'une classe, puis continue avec T comme nom de type utilisé pour le reste de l'expression.

Notez qu'en C++ il n'y a pas de conflit entre le nom de type roman et le nom de variable roman déclaré ici; c'est permis.


Un autre cas de cela peut se produire sans modèles, par exemple:

void func( class bar *ptr );

est correct si bar n'est pas déclaré; il déclare bar puis déclare la fonction pour prendre un pointeur sur bar.

27
M.M