In the example below the function object "rev" is defined in terms of itself. How is this possible?

StackOverflow https://stackoverflow.com/questions/21585339

  •  07-10-2022
  •  | 
  •  

Question

This example (void function f(string& s1, string& s2)) was taken from page 297/298 of B.Stroustup's new book "TCPL" 4th edition.

#include <iostream>
#include <functional>
#include <string>
#include <algorithm>

void f(std::string& s1, std::string& s2)
{
    std::function<void(char* b, char* e)> rev =
                [&](char* b, char* e) { if (1<e-b) { std::swap(*b,*--e); rev(++b,e); } };
    rev(&s1[0],&s1[0]+s1.size());
    rev(&s2[0],&s2[0]+s2.size());
}

int main()
{
    std::string s1("Hello");
    std::string s2("World");
    f(s1, s2);
    std::cout << s1 << " " << s2 << '\n';
}

The code compiles and prints out the correct results, i.e., function f reverses the characters of the input strings. Program output:

olleH dlroW

I can understand the semantics of the expression below. My problem is to accept its syntax, as the variable rev is defined in terms of itself.

std::function<void(char* b, char* e)> rev =
                    [&](char* b, char* e) { if (1<e-b) { std::swap(*b,*--e); rev(++b,e); } 
Était-ce utile?

La solution 2

(From comments beneath question)

Note the subtlety: the point of declaration of rev is, syntactically, exactly at the occurrence of the declarator rev:

                                   // vvv Point of declaration
std::function<void(char* b, char* e)> rev =
    [&](char* b, char* e) { if (1<e-b) { std::swap(*b,*--e); rev(++b,e); }

After that (including the equals sign and everything that follows), rev now represents a valid object with a known type (and size), and it can be used like any other defined variable in scope.

Also, think about how the compiler builds this code:

When it compiles the call to rev (inside the function definition), this is:

  • simply building a stack frame (with known parameters being passed), and
  • calling a jmp (to a known address)

... The actual function being called is irrelevant, as long as its signature and location is known (and the latter information is available to the compiler at the point of declaration).

The rest of the function is, of course, straightforward for the compiler to build, as well.

So, despite the seeming strangeness of 'defining a function in terms of itself', it works straightforwardly.

Autres conseils

The lambda captures everything by reference with [&]. This also includes rev and allows for this syntax.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top