There is such a code:

template<typename T> struct somestruct { ... T somefunction(somestruct<T>* const th = this) { return th ? th->somefield1 : this->somefield2; } ... }; 

Compiler VS 2017 swears:

Error C2355 "this": can only be specified in non-static member functions or initializers of non-static data members

Please explain why I cannot use this in a similar way.

I would like to call somepointer->somefunction(otherpointer) return the pointer object field from the argument if it is not nullptr , otherwise return another field of the pointer object that called the method. And if somefunction is called without arguments, then it would be similar to calling somepointer->somefunction(somepointer) . Of course, you can make such a call explicitly or simply overload somefunction , but I wonder why it is wrong as I wrote.

    2 answers 2

    The short answer is: because the standard of the language says that it is impossible.

    Long answer: in the C ++ language, the formation of default argument values ​​based on the parameters of the function is not allowed.

     void foo(int a, int b, int c = a + b) // Ошибка { ... } 

    this is also an implicit parameter of the non-static class method, so using it to generate the argument value is not allowed by default. The reason for this is, in particular, that it would lead to the need to calculate the parameters of a function in a certain "correct" order, and C ++ does not order and never order the calculation of parameters. † This may not be the only reason for such a ban.

    Instead of the default argument, you can simply use overload and get the desired effect.

     template<typename T> struct somestruct { ... T somefunction(somestruct<T>* const th) { return th ? th->somefield1 : this->somefield2; } T somefunction() { return somefunction(this); } ... }; 

    † Starting from C ++ 17, the calculation of the argument for the implicit parameter this ordered before the calculation of all other arguments. Theoretically, this would have resolved the problem described above with the order of calculation, but so far this has not led to changes in the specification of the use of this in the default arguments.

    • Ahhh, right, I completely missed that this is also a function argument. This, of course, is a gross miscalculation. Thanks for the consultation. - Vlad Sivirin
    • 2
      @AnT "calculating the implicit parameter this is ordered before calculating all other arguments" I correctly understand that this means that in a().b(c()) guaranteed that a() calculated before c() ? - HolyBlackCat 5:28 pm
    • 3
      @HolyBlackCat: Yes, exactly. Paragraph eel.is/c++draft/expr.call#8 and the example with std::string in it is devoted just to this part. - AnT pm

    Perhaps the reason is that while the compiler has not seen the cv qualifiers on the method, the this type is unknown (that is, it is not known, it is a pointer to a constant class or not), and therefore it is forbidden to use it until cv qualifiers.

    Example:

     struct A { auto f1() const -> decltype(this) {return 0;} // Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ `const A *`. auto f2() -> decltype(this) {return 0;} // Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ `A *`. decltype(this) f3() const {return 0;} // Ошибка компиляции, Ρ‚.ΠΊ. ΠΊΠΎΠ³Π΄Π° компилятор Π²ΠΈΠ΄ΠΈΡ‚ // `decltype(this)`, ΠΎΠ½ Π΅Ρ‰Π΅ Π½Π΅ Π·Π½Π°Π΅Ρ‚, константный Π»ΠΈ это ΠΌΠ΅Ρ‚ΠΎΠ΄, ΠΈ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π»ΠΈ `this` Π±Ρ‹Ρ‚ΡŒ // `A *` ΠΈΠ»ΠΈ `const A *`. decltype(this) f3() {return 0;} // Ошибка компиляции, ΠΏΠΎ Ρ‚ΠΎΠΉ ΠΆΠ΅ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π΅. void foo(A * = this) {}; // ΠžΠΏΡΡ‚ΡŒ ΠΆΠ΅, компилятор Π½Π΅ Π·Π½Π°Π΅Ρ‚, ΠΈΠΌΠ΅Π΅Ρ‚ Π»ΠΈ `this` Ρ‚ΠΈΠΏ // `A *` ΠΈΠ»ΠΈ `const A *, поэтому просто Π½Π΅ Π΄Π°Π΅Ρ‚ Π΅Π³ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ. }