On Mar 24, 2021, at 2:02 PM, David Rector <davrec@gmail.com> wrote:

While that does seem like it could be a remotely conceivable usage, which might indeed be absolutely necessary to do truly expert things along the lines of recursively injecting into other fragments, the vast majority of usages of [::] or |##| within a fragment will refer to parameters/local variables declared in the consteval context *enclosing* the fragment (as opposed to within the fragment, as in your example). 

It would be nice if that vast majority of usages did not require %{}.  

A text search over "%" in P2237 shows such usages, which seem to be all the typical uses within fragments. 

Text searches over "|" find examples of || (now [::]) and |##|; there are a few that occur without %{}, however all of these are in a consteval context, rather than within a fragment. E.g. in section 6.1.1:
template<class_type T, structural_subtype_of<T> U> 
void structural_copy(const T& src, U& dst) {
  constexpr auto members = meta::data_members_of(reflexpr(src)); 
  template for (constexpr meta::info a : members) {
    constexpr meta::info b = meta::lookup(dst, meta::name_of(a));
    dst.[:b:] = src.[:a:];

The following proposal seems to me the best solution, which would eliminate %{} from all examples in P2237, while still permitting unusual usages:
  1. (Typical case) Lookup for any declaration referred to in a [::], |##|, or << that is *not enclosed in %{}* will begin in the *most immediate enclosing consteval context*

Can you elaborate what that means?  I have several difficulties in understanding it:
- what is a “declaration referred to in a [::]”?
  (but it feels like a chicken-and-egg issue: how can I know what declaration is referred to
   if I still have to select how I will look up declarations?)
- what is a “consteval context”?


    • Thus [:b:] and [:a:] in `structural_copy` are okay, since they are referenced in a consteval context, and thus lookup begins in the current scope as usual.
    • But for most [::] etc usages within fragments, the most immediate enclosing consteval context is that containing the fragment definition, which is where the parameters/local variables of interest for typical injection tasks usually reside — i.e. see the "property" metafunction in Section 7 of P2237; all the %{} there can be eliminated under this rule.
      • But if you are, say, injecting "structural_copy" into a fragment, lookup for [:a:] and [:b:] would again begin in their current scope, since it is consteval.
  1. (Unusual case) Lookup for any declaration referred to *within %{}* is guaranteed to begin in the current context, regardless of whether or not it is a consteval context.

Note too that the `structural_copy` example happens to reference a `meta::lookup(…)` function which should help the user in still more difficult/fine-grained lookup needs — manually skipping over certain contexts, etc.

On Mar 24, 2021, at 11:34 AM, David Vandevoorde <daveed@edg.com> wrote:

On Mar 23, 2021, at 6:46 PM, David Rector via SG7 <sg7@lists.isocpp.org> wrote:

I’ve come around on most of Andrew’s syntax: [::] seems really to be better than $ after trying it out, considering all the parentheses that would be needed in typical usages, etc.

But there remains a complexity from P2237 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2237r0.pdf) which I am having trouble understanding.  Section 7 contains extensive usage of the "unquote operator" %{}, and discussion of it, particularly in 7.1.7.

Here is the relevant section in its entirety, adjusted to use P2320 syntax (i.e. [::] replaces ||):
> ### 7.1.7 Unquote
> The unquote operator allows the use of local variables and expressions involving local variables inside a fragment. For example:
> ```
consteval meta::info make_fragment(meta::info t) {
  return <struct {
    typename [:%{t}:] obj;
> ```
> The function returns a fragment that includes a splice involving the parameter t. Within the fragment, the unquote operator designates a placeholder for a constant expression. Because an unquoted expression is a placeholder, it is type-dependent, meaning that we need to write typename before the declaration. The value for that placeholder is computed during constant expression evaluation as part of the fragment value and is replaced by its corresponding value during injection.

> The unquote operator can also include more complex expressions:
> ```
consteval meta::info make_fragment(meta::info t) { 
  return <struct {
    typename [:%{meta::add_pointer(t)}:] ptr; 
> ```
> The resulting fragment will inject a pointer to the type reflected by t into the program.

Even with this explanation, I still do not understand the need for %{}.  As an lvalue `t` is already a placeholder for a value, and in each call to `make_fragment` it will already be replaced during constant evaluation with a particular rvalue.  What work does %{} do beyond that?  What am I missing?

More to the point:
 a) Can Andrew & co present an example of an unquote operator usage in which it is plainly necessary, i.e. where the user’s intent is not clear without it?  
 b) Might we adjust the syntax to say the unquote operator is not strictly needed wherever the intent of the user is unambiguous without it?

The unquote operator affects lookup .  Consider:


auto frag = <namespace {
  X* begin(Y) { ... }  // (1)
  bool algo(typename[:%{begin(rs)}:] start) { ... }
     // This `begin` is guaranteed never to find (1).