4

I need to record (for auditing/logging purposes) the code of lambda functions that get passed around in my code. Of course, the lambda object also needs to be saved. So I came up with a macro solution as follows:

#define LAMBDA_AND_STRING(lambda) lambda, #lambda

using namespace std;

int main(int argc, const char * argv[])
{
    auto p = pair<function<void()>, string> ( LAMBDA_AND_STRING( [] {
        cout << "Hello world!" << endl;
        cout << "Hello again!";
    } ) );

    cout << "CODE:" << endl << p.second << endl << endl;

    cout << "EXECUTION:" << endl;
    p.first();
    cout << endl;

}

This outputs:

CODE:
[] { cout << "Hello world!" << endl; cout << "Hello again!"; }

EXECUTION:
Hello world!
Hello again!

That is almost good, but the newlines from the lambda definition are gone (in reality my lambdas are much longer than in the above prototypical example, so keeping the newlines is needed for reasons of readability). Any ideas on how to keep them? (C++11 is fine).

Thanks!

oxfordatnight
  • 255
  • 1
  • 6
  • You could pass the string through a C pretty-printer that automatically adds newlines and indentation appropriate to the code. – Chris Dodd May 24 '23 at 01:39

1 Answers1

4

If I remember correctly, the new lines aren't even part of the argument passed to the macro. It's to do with the order in which whitespace-folding occurs relative to macro expansion, and in effect whitespace is stripped during preprocessor tokenization.

foo.cpp:

#define FOO(a) a

FOO(
    one
    two
    three
)

Result:

$ gcc -E foo.cpp
# 1 "foo.cpp"
# 1 "<command-line>"
# 1 "foo.cpp"


one two three

So you're out of luck, I think. You can do something really nasty to work around it:

#define LAMBDA_AND_STRING(lambda) lambda, #lambda
#define NEWLINE

LAMBDA_AND_STRING( [] { NEWLINE
    cout << "Hello world!" << endl; NEWLINE
    cout << "Hello again!"; NEWLINE
} )

Preprocesses to:

[] { cout << "Hello world!" << endl; cout << "Hello again!"; }, "[] { NEWLINE cout << \"Hello world!\" << endl; NEWLINE cout << \"Hello again!\"; NEWLINE }"

Now replace the NEWLINEs in the string before printing.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • What about using `;;` as line-delimiter ? Shorter, clearer, and no impact on original source without macro. – teh internets is made of catz Nov 02 '13 at 11:44
  • @tehinternetsismadeofcatz: it doesn't impact this source, although it would have an impact on for example a call to an algorithm with several verbose arguments, that has been split across several lines. – Steve Jessop Nov 02 '13 at 15:42
  • I think I can actually live with the "nasty" workaround. It would be nicer to not have to rely on it, but the proper logging/auditing is non-negotiable on this project. So my only alternative would be to write the code twice which is a maintenance nightmare. – oxfordatnight Nov 02 '13 at 17:02
  • ouch. I need my macro expansion to not strip newlines so that \__LINE\__ is preserved. which doesn't seem to be possible... – Michael Feb 05 '16 at 03:18