Is there no such thing as "implicit this parameter" in the Standard?

357 views Asked by At

Recently, I asked this question where one of the answers says:

There's no such thing as "implicit this parameter" in the standard. The standard calls it an "implicit object parameter".

Then someone commented that:

There's no such thing as "implicit this parameter" in the standard." seems wrong. From expr.call#4: "If the function is a non-static member function, the this parameter of the function shall be initialized with a pointer to the object of the call, converted as if by an explicit type conversion."

Seeing the above comment i think that the answer is technically incorrect because the answer said that "There's no such thing as "implicit this parameter" in the standard." while the standard clearly talks about the this parameter.

So how to interpret this further (pun intended)? I mean, it seems that the standard makes a distinction between the non-static member function and a constructor in the context of this parameter. For example, the standard says that for a non-static member function, the this parameter of the function shall be initialized with a pointer to the object of the call converted as if by an explicit type conversion. But the standard doesn't say the same for constructors. So why does the standard makes this distinction? I mean why doesn't the standard says that constructors also have an this parameter that get initialized by the passed argument just like for non-static member functions. This again leads to the deeper question that if there is no this parameter in the constructor unlike non-static member function, then how are we able to use this inside the constructor. For example, we know that we can write this->p = 0 inside the constructor as well as inside a non-static member function, where p is a data member. But in case of non-static member function, this is a parameter of that particular member function so this->p makes sense. But in case of constructor this is not a parameter, so how are we able to use this->p inside the constructor.

Originally, by reading the answers here, I thought that the implicit this parameter is an implementation detail. But after reading expr.call#4 it seems that it is not an implementation detail.

2

There are 2 answers

6
Adrian Mole On

Here's a quotation from this Draft C++17 Standard (bolding for emphasis, and to answer the question, is mine):

10.3.3 The using declaration      [namespace.udecl]



16     For the purpose of forming a set of candidates during overload resolution, the functions that are introduced by a using-declaration into a derived class are treated as though they were members of the derived class. In particular, the implicit this parameter shall be treated as if it were a pointer to the derived class rather than to the base class. This has no effect on the type of the function, and in all other respects the function remains a member of the base class. Likewise, constructors that are introduced by a using-declaration are treated as though they were constructors of the derived class when looking up the constructors of the derived class …

However I should add that the cited paragraph doesn't seem to be present in this later Draft Standard. In fact, that (later) Standard seems to use the phrase, "implicit object parameter," in similar clauses.

So, maybe you should add a specific version tag to your question: or , as there appears to be a divergence in the use (or not) of the term.


Note that the above citation is the only occurrence of the phrase, "implicit this parameter" in that Draft Standard.


Also, note that both documents I have linked are only Draft versions of the respective Standards, and both come with this cautionary escape-clause:

Note: this is an early draft. It’s known to be incomplet and incorrekt, and it has lots of bad formatting.

2
paxdiablo On

If you think this is some sort of implicit parameter, type in this code:

#include <iostream>

struct SimpleThing {
    int xyzzy;
    SimpleThing(): xyzzy(42) {}
    void print(int plugh, const int twisty) {
        std::cout << xyzzy << '\n';
        std::cout << plugh << '\n';
        std::cout << twisty << '\n';
        xyzzy = 0;
        plugh = 0;
        twisty = 0;
        this = 0;
    }
};

int main() {
    SimpleThing thing;
    thing.print(7, 99);
}

Then examine the errors you get:

prog.cpp: In member function ‘void SimpleThing::print(int, int)’:
prog.cpp:12:16: error: assignment of read-only parameter ‘twisty’
   12 |         twisty = 0;
      |         ~~~~~~~^~~
prog.cpp:13:16: error: lvalue required as left operand of assignment
   13 |         this = 0;
      |                ^

Note that the first two assignments work because they are modifiable variables. The third fails because it is, of course, (non-modifiable) const.

The attempted assignment to this doesn't look like any sort of "can't write to some sort of variable" diagnostic because it actually isn't.

The this keyword is a special marker inside non-static member functions (and constructors/destructors) that is translated into the address of the object being worked upon. While it may be passed as a hidden parameter, that is very much an implementation detail with which the standard does not concern itself.

The controlling section in the C++20 standard is in [class.this]:

In the body of a non-static member function, the keyword this is a prvalue whose value is the address of the object for which the function is called.

Nowhere in there (the entire section) does it mention that this is some sort of hidden parameter to the call.


And, regarding your question on why there is a distinction between non-static member functions and constructors, I don't believe this distinction involves the existence of this in either case, it instead has to do with the qualification of the type of this. It's existence in a constructor is undeniable as [class.ctor] states:

During the construction of an object, if the value of the object or any of its subobjects is accessed through a glvalue that is not obtained, directly or indirectly, from the constructor’s this pointer, the value of the object or subobject thus obtained is unspecified.

In other words, I see your quote:

If the function is a non-static member function, the this parameter of the function is initialized with a pointer to the object of the call, converted as if by an explicit type conversion.

as specifying only the qualification of this, something that the constructor doesn't need.

There is no discussion of cv-qualified conversion for constructors as there is for other member functions because you can't actually create a cv-qualified constructor. It would be rather useless if your constructor were not allowed to set any member variables, for example :-)

While constructors can be used to create cv-qualified objects, the constructor itself is not cv-qualified. This is covered at the end of [class.this]:

Constructors and destructors shall not be declared const, volatile or const volatile. [Note: However, these functions can be invoked to create and destroy objects with cv-qualified types - end note]

And further in [class.ctor]:

A constructor can be invoked for a const, volatile or const volatile object. Const and volatile semantics are not applied on an object under construction. They come into effect when the constructor for the most derived object ends.


To be honest, I think WG21 would be better off going through the next iteration and replacing things like "the this parameter of the function" with a phrase that does not mention parameters at all (such as "the this property".