C++ Logo

sg7

Advanced search

Re: [SG7] Metaprogramming

From: Andrew Sutton <asutton.list_at_[hidden]>
Date: Sun, 25 Oct 2020 10:54:44 -0400
>
>
>> 1. Some additional code added to the Lexer/Preprocessor (nothing in
>> the hot path), similar to the functionality used to expand macros.
>> 2. Some additional logic needed to add "metaparsed" Decls into
>> template instantiations (setting up scopes etc.).
>> 3. There may be issues when the user calls macros in the code strings
>> (e.g. `__metaparse("int SOMEMACRO(foo) = 4")`) — I got crashes early on,
>> added checks and diagnostics to address them, but they were needed in a
>> number of strange spots so a more comprehensive consideration would be
>> warranted.
>> 4. Would be nice if diagnostics could point inside a string literal,
>> e.g.
>>
>> ```
>> __metaparse("int i = missspelling;");
>> ^ unknown identifier
>> ```
>>
>> It’s been awhile but I think that covers it.
>>
>
> I have no doubt that you can get simpler cases working this way. But the
> way we process source during parsing and during template instantiation are
> fundamentally different, so I'd expect lots of things to not work (for
> example, you won't be able to do lookups that find local variables when
> injecting into a function scope).
>
> But honestly, I don't think implementation complexity is the primary
> reason we shouldn't do this. I think the better reason is that such an
> approach is fundamentally distasteful and unhygienic in much the same way
> that macros are. You know what's worse than a vexing parse bug? A vexing
> parse bug caused by a compile-time program spitting out an ambiguous string
> of C++ code. Good metaprogramming is semantic, not based on what a string
> happens to mean when interpreted in a particular context.
>

Exactly this.

My work on injection (2015 or 16 I think) started using tokens, but moving
to strings is not a big jump. The implementation isn't really hard. What
killed that approach was the fact that names in the fragment/token
sequence/string are completely reinterpreted at the point that you inject
them. Those names that you thought referred to types suddenly don't when
injected. If you're lucky, you get compiler errors. If you're unlucky, you
can also get runtime bugs.

I spent a month or so trying to find ways to alleviate those problems, but
still using macros and ended up with a weird kind-of-like-C++ grammar that
mostly worked, but only in trivial cases. So, I looked at using templates
as a basis for injection. The underlying concepts aren't too fundamentally
different.

Anyway, all of that "needless complexity" in fragments aims to provide a
strong guarantee that the code injected into a program has the meaning
intended when it was written. And actual users don't seem to have been
terribly burdened by the model.

Received on 2020-10-25 09:54:57