C++ Logo

sg16

Advanced search

Re: Follow up on SG16 review of P2996R2 (Reflection for C++26)

From: Tom Honermann <tom_at_[hidden]>
Date: Sun, 28 Apr 2024 14:36:11 -0400

On Apr 28, 2024, at 12:57 PM, Victor Zverovich <victor.zverovich_at_[hidden]> wrote:


> Is support for std::cout specifically required or would support for std::format() and std::print() suffice? If std::cout support is specifically required, what motivates that requirement?

Not an author, but it would be very novel and potentially surprising to users to not support std::cout for such a fundamental thing as a reflected name.

There will always be some way to print a name. The question is what machinations will be required to do so and what quality result will be achieved. 

We have no way to ensure that a name will actually be rendered as a recognizable sequence of glyphs; we can’t make an EBCDIC or CP437 terminal display all valid identifiers no matter what lengths we go to. std::print() does an objectively better job (on Windows) than std::cout is capable of (without the application first calling a number of Windows specific functions that we cannot do on its behalf), but it can’t overcome font limitations and does nothing for EBCDIC-based systems.

We can provide a best effort default behavior, but regardless, some subset of users will likely have to apply their own transformations to satisfy their needs subject to the restrictions of their environment.

We don’t have a lot of precedent to draw on here. I think the closest we have is the conditional display of “μs” vs “us” in https://eel.is/c++draft/time.duration.io#1.5.

Tom. 


- Victor

On Sun, Apr 28, 2024 at 8:49 AM Tom Honermann via SG16 <sg16_at_[hidden]> wrote:

SG16 reviewed P2996R2 (Reflection for C++26) during its 2024-04-24 meeting and will continue review during the 2024-05-08 SG16 meeting. I am working on the meeting summary for the previous meeting now and hope to publish it in the next few days. In the meantime, I wanted to get some discussion going to help prepare for our next review (in ~10 days).

Daveed's presentation slides are available here for anyone that would like to review them. They appear to have had some minor updates since the SG16 review (e.g., slide 10 is new).

Slide 6 lists some requirements for the design. These include:

  • Round-tripping must work (e.g., names returned by name_of() must be valid input to data_member_spec() via data_member_options_t::name).
  • Output to std::cout must work reasonably (e.g., std::cout << name_of(^int)).
  • Some text may not be source-like text (std::meta::display_name_of).

I would like to further clarify these requirements. P2996R2 authors, please answer the following questions.

Are names returned by qualified_name_of() required to be round-trippable?

Is support for std::cout specifically required or would support for std::format() and std::print() suffice? If std::cout support is specifically required, what motivates that requirement?

Are all of name_of(), qualified_name_of(), and display_name_of() required to return text (perhaps not source-like text, but content that is nevertheless text)? In other words, can they be guaranteed to provide well-formed text in some encoding?

During the meeting, we briefly discussed use of an opaque type for the return type of name_of() and friends. I would like to see further exploration of this idea prior to our next review. I'm envisioning a type something like the following (This particular formulation follows existing precedent established by the std::filesystem::path native format observers, [fs.path.native.obs]).

class name {
  std::string_view internal-representation; // exposition only.
  name(/* unspecified */);
public:
  constexpr std::string string()       const; // ordinary literal encoding.
  constexpr std::wstring wstring()     const; // wide literal encoding.
  constexpr std::u8string u8string()   const; // UTF-8.
  constexpr std::u16string u16string() const; // UTF-16.
  constexpr std::u32string u32string() const; // UTF-32.
};

The intent is that the data accessed by the internal-representation member has static storage duration; perhaps a string literal. The observers would then provide access to the name in the above encodings. If I'm not mistaken, this should enable use of these names in std::basic_string objects during constant evaluation (so long as the object's lifetime is appropriately constrained) and run-time while only requiring static persistence of the internal representation.

Support for all five of the standard specified encodings is not necessarily required. SG16 can provide a recommendation for LEWG. The paper should discuss the pros, cons, and implementation costs for support of each encoding. Given existing precedent, lack of support for any given encoding should be motivated.

Note that the above type suffices to provide support for printing names via std::cout, std::format(), and std::print(). A iostream insertion operator and/or a std::formatter specialization could be defined to enable printing names without having to call one of the member functions.

If I understand the intent correctly (it would be helpful to clarify this in a revision of the paper), names returned by name_of() do not reflect a scope but do not necessarily reflect an identifier either. For example, something like "operator bool" might be returned. Tangentially, I think the formatting of names accepted by data_member_spec() needs to be rigorously specified for programs to be portable.

We will need to make a decision regarding how characters that lack representation in the ordinary and wide literal encodings are to be handled. We have a few options.

  1. Don't provide the above string() and wstring() member functions.
  2. Constrain the above string() and wstring() member functions so that they are not callable (e.g., does not participate in overload resolution...) if the associated literal encoding is unable to represent all characters that might appear in an identifier.
  3. Specify that the above string() and wstring() member functions fail constant evaluation or throw an exception (or similar error handling) if the name uses a character that is not representable in the associated literal encoding.
  4. Specify a way to encode non-representable characters in the names returned by the above string() and wstring() member functions and specify that data_member_spec() accepts such encoded names.

If data_member_spec() is modified to accept names specified by a class like name above, then it will be necessary to specify a way to construct an object of that type with a name constructed during constant evaluation. Assuming the internal-representation format is unspecified, this will require means to construct that format in a buffer with a lifetime that matches the lifetime of the constructed object.

Tom.

--
SG16 mailing list
SG16_at_[hidden]
https://lists.isocpp.org/mailman/listinfo.cgi/sg16

Received on 2024-04-28 18:36:25