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!
7 Réponses :
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
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
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.
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
indique clairement que value
est un membre de la classe modèle Factorial
value
est un champ statique
de la classe.
#include <iostream> int main() { std::cout << "hi!\n"; // access the object 'cout' in the namespace 'std' }
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
est un identifiant qualifié .:: value
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 exemplestd :: string :: npos
signifie approximativement trouver le membre de données appelénpos
dans la classe appeléestring
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èleFactorial
pourN = 3
, ce qui signifie que nous avons maintenant une classe concrète non-templateFactorial
équivalente auF_3 code> J'ai écrit manuellement ci-dessus.
La définition de cette classe fait référence à
Factorial
(avec:: value N-1 = 2 code >), donc
Factorial
est également instancié. Cette chaîne d'instanciations implicites continue jusqu'à ce que nous atteignions leFactorial
explicitement spécialisé (sans cela, il continuerait à essayer d'instancierFactorial
,Factorial
, pour toujours jusqu'à ce que le compilateur abandonne et échoue).
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é.
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.
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.
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'; }
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.