C++ Logo

sg7

Advanced search

Re: [SG7] Incomplete types

From: Andrew Sutton <asutton.list_at_[hidden]>
Date: Mon, 2 Nov 2020 11:00:36 -0500
> This seems counterintuitive to me. I consider `sizeof` and `decltype` a
> poor version of a reflection and you can do this:
>
> struct X {
>
> int a;
> static constexpr unsigned size = sizeof(X::a);
> using type = decltype(X::a);
>
> };
>
> https://compiler-explorer.com/z/9f7WKn
>
> Even when the type is not yet complete. I personally think we should
> support such cases.
>

Default member initializers are parsed in a complete-class-context",
essentially meaning the parsing is delayed until the closing } of the
class. This is why lookup works in those cases. The same is true of default
arguments, inline member function bodies, and noexcept-specifiers.

My mental model of injection via conseval blocks is very simple. First,
consteval blocks have the guarantee that they are executed where they
appear or where they're instantiated if they appear in a template. After
the metaprogram runs, the compiler effectively "pastes" the injected code
over top of the metaprogram as if you had manually typed in. Of course,
whatever rules and restrictions apply to hand-written code also apply to
metaprograms.

Adding consteval blocks to the complete-class-context might make lookups
work in metaprograms, but that also breaks this very simple model.
Consteval blocks are no longer guaranteed to execute where they appear, but
rather sometime later. 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.
};

I think it also makes reasoning about injection much harder because the
complete-class-context defers analysis to the outermost enclosing class.

struct s {
  struct t {
    consteval { /* inject code */ };
  }; // metaprogram is not run here
}; // metaprogram runs here

This potentially makes the implementation a bit harder too, since we'd have
to re-establish the full context where the consteval block was parsed
before executing it.

Andrew

Received on 2020-11-02 10:00:50