3
votes

Que fait l'opérateur :: dans cette situation

template <int N>
struct Factorial {
  static const int value = N * Factorial<N - 1>::value;
};

// Base case via template specialization:

template <>
struct Factorial<0> {
  static const int value = 1;
};
So I might have figured out that here the role of the '::' operator is to somehow feed/add into the 'value' variable the content of the operation performed earlier (N * Factorial). But can someone explain this in a more thorough manner (I wouldn't mind a full explanation of the '::' operator roles).Thank you very much!

9 commentaires

L'opérateur :: fait la même chose dans tous les cas. Il accède au nom à droite depuis l'intérieur du nom à gauche.


:: est un opérateur de résolution de portée .


related / dupe: stackoverflow.com/questions/ 3082113 /… Il explique ce qui se passe ici, pas exactement ce que :: est


Le code @NathanOliver est la même question est différente, donc pas une dupe.


@NathanOliver et Marek R, je trouve en fait cet autre fil utile, car j'essaie toujours de comprendre le retour en arrière que cet algorithme implique (pas l'algorithme réel, mais la manière dont la variable `` valeur '' est instanciée et mise à jour ). À votre santé!


Vous devriez récupérer une copie des modèles C ++ et apprendre comment fonctionne la méta-programmation des modèles. Ceci est un exemple assez basique pour illustrer la puissance des modèles C ++. Btw, :: n'a pas besoin de modèles pour fonctionner.


@Tanveer Badar Avez-vous des suggestions? Je suis actuellement orienté vers cppreference.com et Bjarne Stroustup 'Programming Principles and Practice 4ème édition où il parle un peu de templates.


Je vois aussi que dans 'A Tour of C ++' (par Bjarne Stroustrup) le 6ème chapitre va en profondeur sur les Templates. Je vais aussi vérifier ça


cppreference.com est juste cela, une référence - bien que très bonne et presque complète. Les modèles C ++ sont un excellent livre pour la métaprogrammation, même si je dois admettre que je ne l'ai pas encore lu en détail. Le langage de programmation C ++ est également bon, quelle que soit l'édition que vous pouvez obtenir, mais préférez la 4ème édition si vous le pouvez. Les sections de référence et de langage C ++ de MSDN sont une bonne source, mais quel que soit le code que vous écrivez après l'avoir lu, assurez-vous de l'exécuter également via GCC / Clang pour éliminer tout élément spécifique à MSVC.


7 Réponses :


1
votes

La classe de modèle

struct Factorial résout la valeur à partir de struct Factorial et à chaque fois la valeur est résolu récursivement. Et à la fin, la valeur sera 1 à partir du cas de base suivant:

Factorial<5> f;
std::cout << f.value << std::endl;

la valeur détermine ici:

template <>
struct Factorial<0>

Ainsi, la sortie sera: 120


2 commentaires

Ce n'est plus incorrect. Permettez-moi de retirer mes commentaires précédents.


veuillez ne pas approuver automatiquement les modifications incorrectes qui transforment le code en extrait de code comme vous l'avez fait ici: stackoverflow.com / review / suggestions-edits / 23586198 .. l'OP utilise un code SASS et il est très mauvais que la question en fasse un extrait



2
votes

Si vous avez une classe foo avec un membre statique bar , vous pouvez y faire référence avec la :: notation comme foo :: bar .

Ici, Factorial est une classe, avec une valeur de membre statique. Mis à part la notation du modèle, il n'y a aucune différence.


0 commentaires

6
votes

L'opérateur :: est appelé l'opérateur de résolution de portée. Il «résout» ou clarifie la portée dans laquelle se trouve l'opérande de droite, un nom de variable.

Par exemple, std :: cout indique clairement au compilateur que l'identifiant cout doit être recherché dans l'espace de noms std . Dans votre cas, la Factorial :: value indique clairement que value est un membre de la classe modèle Factorial < / code>. Il est utilisé ici car value est un champ statique de la classe.


0 commentaires

1
votes
#include <iostream>

int main()
{
   std::cout << "hi!\n";  // access the object 'cout' in the namespace 'std'
}

0 commentaires

6
votes

Alors j'aurais peut-être compris que

Je suggère fortement d ' apprendre C ++ à partir d'un livre, et d'apprendre à utiliser le matériel de référence existant, plutôt que d'essayer de comprendre ce que signifie un code à partir des premiers principes. Vous risquez très probablement de faire des erreurs subtiles si vous faites des suppositions éclairées.

L'expression Factorielle :: value est un identifiant qualifié .

Factorial code> est le nom d'une classe (une instanciation du modèle Factorial avec une valeur spécifique pour le paramètre unique). Cette classe a un membre de données appelé valeur . Une qualification explicite est nécessaire car cette valeur particulière n'est pas autrement dans la portée. Voir aussi recherche de nom qualifié .

Vous pouvez utiliser :: comme ceci pour n'importe quel membre de classe: par exemple std :: string :: npos signifie approximativement trouver le membre de données appelé npos dans la classe appelée string dans l'espace de noms appelé std.

... en quelque sorte alimenter / ajouter dans la variable 'value' le contenu de l'opération effectuée précédemment ...

il n'y a pas de "plus tôt", tout se passe au cours de la même étape de compilation.

Par exemple, je peux écrire manuellement

struct F_0 { static const int value = 1; }
struct F_1 { static const int value = 1 * F_0::value; }
struct F_2 { static const int value = 2 * F_1::value; }
struct F_3 { static const int value = 3 * F_2::value; }

etc. etc. pour autant de valeurs que je veux. La version basée sur un modèle est effectivement la même mais économise beaucoup de frappe.

Plus précisément, l'écriture de Factorial instancie le modèle Factorial pour N = 3 , ce qui signifie que nous avons maintenant une classe concrète non-template Factorial équivalente au F_3 code> J'ai écrit manuellement ci-dessus.

La définition de cette classe fait référence à Factorial :: value (avec N-1 = 2 code >), donc Factorial est également instancié. Cette chaîne d'instanciations implicites continue jusqu'à ce que nous atteignions le Factorial explicitement spécialisé (sans cela, il continuerait à essayer d'instancier Factorial , Factorial , pour toujours jusqu'à ce que le compilateur abandonne et échoue).


2 commentaires

Je reconnais qu'il me reste encore beaucoup à apprendre et je tiens également à vous remercier pour votre réponse compétente.


De plus, par «plus tôt», je l'entendais comme écrit auparavant dans le code; Je ne voulais pas que cela soit interprété comme une mesure du temps écoulé.



-3
votes

L'opérateur ':: -' est utilisé pour accéder aux choses dans les espaces de noms (std :: string) ou aux choses statiques dans une classe:

struct C {
    static int i = 42;
};
int main() {
    std::cout << C::i << '\n';
}

Ici C :: i est statique, donc Je n'ai pas besoin d'une instance de la classe C. Pour accéder à quelque chose non statique dans une classe, vous utilisez un «.». Dans votre exemple, Factorial n'est pas une classe mais un modèle, Factorial est une classe et Factorial :: value est la valeur statique int à l'intérieur de la classe Factorial.


1 commentaires

un namespace en C ++ est un concept distinct. Vous voulez dire portée ici, car basic_string définit une classe, qui est une portée et non un espace de noms.



1
votes

Pour rendre cela plus clair, envisagez un accès alternatif à l'élément de données value.

479001600

La sortie du programme est

#include <iostream>

template <int N>
struct Factorial {
  static const int value = N * Factorial<N - 1>().value;
};

// Base case via template specialization:

template <>
struct Factorial<0> {
  static const int value = 1;
};

int main()
{
    std::cout << Factorial<12>().value << '\n';
}


0 commentaires