C++ Logo

SG7

Advanced search

Subject: Re: Incomplete types
From: Wyatt Childers (wchilders_at_[hidden])
Date: 2020-11-02 14:05:06


I believe what you're thinking of is from within a fragment
https://cppx.godbolt.org/z/bazc9K:

    class foo {
     Â  consteval {
     Â Â Â  -> fragment struct {
     Â Â Â Â Â  foo bar() { // this isn't okay, foo is incomplete
     Â Â Â Â Â Â Â  return {};
     Â Â Â Â Â  }
     Â Â Â  };
     Â  }
    };

You can of course express the same idea, however you need to do this
indirectly (so that injection can sew things together for you, at the
right time):

    class foo {
     Â  consteval {
     Â Â Â  -> fragment struct {
     Â Â Â Â Â  typename |%{reflexpr(foo)}| bar() {
     Â Â Â Â Â Â Â  return {};
     Â Â Â Â Â  }
     Â Â Â  };
     Â  }
    };

Also, consider injection into another context (e.g. inject foo
global_bar() { return { }; } into the global namespace):

 Â Â Â  class foo {
 Â Â Â Â Â  consteval {
 Â Â Â Â Â Â Â  -> namespace(::) fragment namespace {
 Â Â Â Â Â Â Â Â Â  typename |%{reflexpr(foo)}| global_bar() {
 Â Â Â Â Â Â Â Â Â Â Â  return {};
 Â Â Â Â Â Â Â Â Â  }
 Â Â Â Â Â Â Â  };
 Â Â Â Â Â  }
 Â Â Â  };

This injection is delayed until the class is complete, and then injected
into the global namespace -- allowing the compiler to work with this
code "in the usual way".

------------------------------------------------------------------------

    That means you can't rely on declarations assumed to have been injected

        template<typename T>
        struct my_class {
         Â Â  consteval { -> inject_useful_decl<T>(); }
         Â Â  decltype(useful_decl) var; // oops. error: no useful_decl
        declared.
        };

Correct, this doesn't work, as the consteval block doesn't execute until
the template is instantiated (https://cppx.godbolt.org/z/97v6Wr).

------------------------------------------------------------------------

    I don't think we have to make consteval blocks part of the
    complete-class context of the enclosing class.  Lookup already
    works.  We just have to ensure that it is clear that some properties
    of nonstatic data members aren't queryable.

    struct S {
    int a;
    consteval {
     Â  -> inject_useful_decl<typename(reflexpr(S::a))>(); // Okay.
    }
    consteval {
     Â  -> inject_other<meta::offset_of(reflexpr(S::a))>();  // Error.
    }
    };

    A question we'd have to answer is whether a reflection of a
    nonstatic data member obtained while the class is still incomplete
    would remain valid after the class is completed, and, if so, whether
    the completeness would be reflected in that reflection (so that,
    e.g., querying the offset later on would work).  IMO, the answer
    should be yes to both of those.

Agreed, on all points.

On 11/2/20 2:03 PM, Andrew Sutton via SG7 wrote:
>
>>
>> Default member initializers are parsed in a
>> complete-class-context", essentially meaning the parsing is
>> delayed until the closing } of the class.
>
> Right, but Hana's two examples aren't in such contexts, and we
> permit them anyway.  Lookup succeeds, but some operations (like
> offsetof) aren't permitted.
>
>
> Wow. I am not reading well today.
>
>> Adding consteval blocks to the complete-class-context might make
>> lookups work in metaprograms, but that also breaks this very
>> simple model.
>
> I don't think we have to make consteval blocks part of the
> complete-class context of the enclosing class. Lookup already
> works.  We just have to ensure that it is clear that some
> properties of nonstatic data members aren't queryable.  E.g.:
>
> struct S {
>   int a;
> consteval {
> -> inject_useful_decl<typename(reflexpr(S::a))>(); // Okay.
>   }
> consteval {
> -> inject_other<meta::offset_of(reflexpr(S::a))>();  // Error.
>   }
> };
>
> A question we'd have to answer is whether a reflection of a
> nonstatic data member obtained while the class is still incomplete
> would remain valid after the class is completed, and, if so,
> whether the completeness would be reflected in that reflection (so
> that, e.g., querying the offset later on would work). IMO, the
> answer should be yes to both of those.
>
>
> I must be forgetting where lookup fails, but we've definitely run into
> issues requiring complete class types in *some* contexts. Wyatt can
> probably answer that question better than I can at this point.
>
>
>



SG7 list run by sg7-owner@lists.isocpp.org

Older Archives on Google Groups