3
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!

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
dreamer
  • 161
  • 1
  • 8
  • 4
    The `::` operator does the same thing in all cases. It access the name on the right from inside the name on the left. – NathanOliver Jul 19 '19 at 13:56
  • 1
    `::` is a [scope resolution operator](https://en.wikipedia.org/wiki/Scope_resolution_operator). – Marek R Jul 19 '19 at 13:58
  • related/dupe: https://stackoverflow.com/questions/3082113/calculating-factorial-using-template-meta-programming It explains what is happening here, not exactly what :: is – NathanOliver Jul 19 '19 at 13:59
  • 1
    @NathanOliver code is same question is different, so not a dupe. – Marek R Jul 19 '19 at 14:00
  • @NathanOliver and Marek R, I actually find that other thread useful, as I am still trying to wrap my head around the backtracking this algorithm implies (not the actual algorithm, but the way in which the 'value' variable is being instantiated and updated). Cheers! – dreamer Jul 19 '19 at 15:43
  • You should grab a copy of C++ templates and learn how template meta-programming works. This is a fairly basic example to illustrate the power of C++ templates. Btw, `::` does not need templates to work. – Tanveer Badar Jul 19 '19 at 18:15
  • @Tanveer Badar Do you have any suggestion? I am currently geared towards cppreference.com and Bjarne Stroustup' Programming Principles and Practice 4th edition where he does speak a bit about templates. – dreamer Jul 20 '19 at 08:53
  • I also see that in 'A Tour of C++' (by Bjarne Stroustup) the 6th chapter goes in depth about Templates. I'll also check that out – dreamer Jul 20 '19 at 09:17
  • cppreference.com is just that, a reference - though a very good and nearly complete one. C++ templates is a great book for metaprogramming, though I must admit I haven't read it in any detail yet. The C++ programming language is also good, whatever edition you can get but prefer 4th edition if you can. MSDN's C++ reference and language sections are good source, but whatever you code write after reading that, be sure to run it through GCC/Clang too to root out any MSVC specific stuff. – Tanveer Badar Jul 20 '19 at 14:25

7 Answers7

6

The :: operator is called the scope resolution operator. It "resolves," or makes clear, the scope in which the right-hand operand, a variable name, is located.

For example, std::cout makes it clear to the compiler that the identifier cout should be searched for in the namespace std. In your case, the Factorial<N - 1>::value makes it clear that value is a member of the templated class Factorial<N - 1>. It's used here because value is a static field of the class.

lost_in_the_source
  • 10,998
  • 9
  • 46
  • 75
6

So I might have figured out that

I strongly suggest learning C++ from a book, and learning to use existing reference material, rather than trying to figure out what some code means from first principles. You're very likely to make subtle mistakes if you go by educated guesses.

The expression Factorial<N - 1>::value is a qualified identifier.

Factorial<N - 1> is the name of a class (an instantiation of the Factorial<int> template with a specific value for the single parameter). This class has a data member called value. Explicit qualification is needed since this particular value isn't otherwise in scope. See also qualified name lookup.

You can use :: like this for any class member: for example std::string::npos roughly means find the data member called npos in the class called string in the namespace called std.

... somehow feed/add into the 'value' variable the content of the operation performed earlier ...

there is no "earlier", this all happens during the same stage of compilation.

For example, I can manually write

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. for as many values as I want. The templated version is effectively the same but saves a lot of typing.

Specifically, writing Factorial<3> instantiates the template Factorial<int N> for N=3, which means we now have a concrete non-template class Factorial<3> equivalent to the F_3 I wrote manually above.

The definition of this class refers to Factorial<N-1>::value (with N-1 = 2), so Factorial<2> gets instantiated too. This chain of implicit instantiations continues until we reach the explicitly specialized Factorial<0> (without that, it'd keep trying to instantiate Factorial<-1>, Factorial<-2>, forever until the compiler gave up and failed).

Useless
  • 64,155
  • 6
  • 88
  • 132
  • I agree that there is still much I need to learn and I also want to thank you for the competent reply. – dreamer Jul 19 '19 at 14:20
  • Also, by 'earlier' I meant it as in written before in the code; I didn't want it to be interpreted as in a measure of time passed. – dreamer Jul 20 '19 at 08:55
2

If you have a class foo with a static member bar, then you can refer to it with the :: notation as foo::bar.

Here, Factorial<N - 1> is a class, with a static member value. Asides from the template notation, there is no difference.

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
1

struct Factorial template class resolves value from struct Factorial<N - 1> and each time the value is resolves recursively. And at the end the value will be 1 from the following base case :

template <>
struct Factorial<0>

the value determine here :

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

So, the output will be : 120

  • Not incorrect anymore. Let me retract my previous comments. – Tanveer Badar Jul 20 '19 at 14:22
  • please don't automatically approve *bad* edit that turns code into snippet like you did here: https://stackoverflow.com/review/suggested-edits/23586198 .. the OP is using a SASS code and it's very bad for the question to make it a snippet – Temani Afif Jul 21 '19 at 19:14
1
static const int value = N * Factorial<N - 1>::value

It means that the value of the member Factorial<N>::value is N multiplied by the value of the member Factorial<N-1>::value. (Except for Factorial<0>::value, which is specialised to provide a recursive base case)

Both Factorial<N> and Factorial<N-1> are classes.

:: is the scope resolution operator and tells the compiler that you want to access a member (in this case, a static member) of the class (or namespace) to the left of it.

A simpler example:

class Foo
{
    static int x;
};

int Foo::x = 42;

int main()
{
   int y = Foo::x;  // access the member 'x' in the class 'Foo'
}

or:

#include <iostream>

int main()
{
   std::cout << "hi!\n";  // access the object 'cout' in the namespace 'std'
}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

To make it more clear consider an alternative access to the data member value.

#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';
}

The program output is

479001600

Here is used the member access expression Factorial<N - 1>().value or Factorial<12>().value.

So to specify an access to the data member value (and especially for non-static data members) you create an object of the type Factorial<N - 1> or Factorial<12>.

But static data members do not require an object of the class to be created. So it is much simpler and safer to use a class name and the operator :: to specify an access to a static data member.

The member access expression Factorial<N - 1>::value specifies that value is a static data member of the class Factorial<N - 1>. Neither object of the class Factorial<N - 1> is required. It is enough to specify the name of the class to which the static data member belongs.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
-3

The '::-operator' is used to access things in namespaces (std::string) or static things in a class:

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

Here C::i is static, so I don't need an instance of class C. To access some non-static thing inside a class you use a '.'. In your example Factorial is no class but a template, Factorial is a class and Factorial::value is the static int value inside the class Factorial.

Humm
  • 75
  • 4
  • a `namespace` in C++ is a distinct concept. You mean to say scope there, as basic_string defines a class, which is a scope not a namespace. – Tanveer Badar Jul 19 '19 at 14:03