Skip to content

Conversation

hewillk
Copy link
Contributor

@hewillk hewillk commented Sep 8, 2025

These two constructors should also be exposition-only, so it makes sense to add exposition-only for them?

@eisenwave
Copy link
Member

eisenwave commented Sep 9, 2025

No, this edit seems wrong. You're looking at a constructor of an exposition-only type, and it feels redundant to add // exposition only to that. It would be inconsistent with other places such as the constructor of sender-awaitable (https://eel.is/c++draft/exec.as.awaitable#2)

To be fair, the style is inconsistent in another way: sender-awaitable makes only private members exposition-only, but cw-fixed-value makes even its public members (except for the constructor) exposition-only. This inconsistency may be unintentional; I certainly don't see the point in making public members of exposition-only types additionally exposition-only (nor any other member tbh).

@jwakely thoughts?

@hewillk
Copy link
Contributor Author

hewillk commented Sep 9, 2025

No, this edit seems wrong. You're looking at a constructor of an exposition-only type, and it feels redundant to add // exposition only to that. It would be inconsistent with other places such as the constructor of sender-awaitable (https://eel.is/c++draft/exec.as.awaitable#2)

In <ranges>, many constructors of an exposition-only class are explicitly specified as exposition-only.

I certainly don't see the point in making public members of exposition-only types additionally exposition-only (nor any other member tbh).

It does not matter. Whether it is public or not, exposition-only means it does not exist. There are some public functions are also exposition-only, such as split_view::find-next.

@frederick-vs-ja
Copy link
Contributor

Looks like that we should introduce a way to specifying that only the name of the member, but not any other aspect, is exposition-only.
There's previously LWG2310 touching an exposition-only but public data member, but its resolution seemingly made std::array less specified.

@frederick-vs-ja
Copy link
Contributor

Whether it is public or not, exposition-only means it does not exist.

This isn't quite correct. "Exposition-only" means that it doesn't exist in the that exact form, but its effect must be specified (in some degree), per [objects.within.classes]/3. It might be a defect that [objects.within.classes] doesn't seem to cover non-private exposition-only members.

I'm quite sure that it's currently required that the following program is well-formed (Godbolt link):

#include <type_traits>

template<class>
struct ExtractCW {};
template<auto V, class T>
struct ExtractCW<std::constant_wrapper<V, T>> {
  using type = decltype(V);
};

template<auto V>
using ExtractedCWFixedValue = ExtractCW<std::remove_cvref_t<decltype(std::cw<V>)>>::type;

int main() {
  ExtractedCWFixedValue<1> x = 1;
}

If we change the constructors to be exposition-only, either it would be unspecified whether this program is well-formed, or it would be required that this program is ill-formed. Maybe it's unintended to precisely specify cw-fixed-value to behave like this, but I think we need to change it via an LWG issue.

@hewillk
Copy link
Contributor Author

hewillk commented Sep 9, 2025

Maybe it's unintended to precisely specify cw-fixed-value to behave like this, but I think we need to change it via an LWG issue.

That doesn't seem to be the intention.
If it were the intention, then the CTAD of cw-fixed-value(T (&)[Extent]) should also be NON-exposition-only.

@jwakely
Copy link
Member

jwakely commented Sep 9, 2025

It does not matter. Whether it is public or not

It certainly does matter, because if it was shown as a private member it would make the type non-structural, and it couldn't be used as a template parameter, and constant_wrapper wouldn't work.

@jwakely
Copy link
Member

jwakely commented Sep 9, 2025

No, this edit seems wrong. You're looking at a constructor of an exposition-only type, and it feels redundant to add // exposition only to that. It would be inconsistent with other places such as the constructor of sender-awaitable (https://eel.is/c++draft/exec.as.awaitable#2)

I agree the edit is wrong, but not because it's redundant.

There needs to be a way for the compiler to construct this type from a value, and we need to be able to specify that the data member is initialized to the value of the initializer. Guaranteeing that this constructor is present makes that work, so I think the name of the type, and the name of the data member, and the name of the type type, are unspecified and shown with those names for exposition, but we do want to specify that some type of this form exists and has a constructor that allows it to be initialized.

To be fair, the style is inconsistent in another way: sender-awaitable makes only private members exposition-only, but cw-fixed-value makes even its public members (except for the constructor) exposition-only. This inconsistency may be unintentional; I certainly don't see the point in making public members of exposition-only types additionally exposition-only (nor any other member tbh).

Because the types are frequently accessible to users, e.g. the exposition-only iterator type in views are visible to users as decltype(v.begin()). The point of making public members exposition-only is so that users cannot rely on those members existing with that name. And the point of making some members public (as in sender-awaitable) is that users absolutely are upposed to be able to rely on those members existing. Like operator++ on a view iterator, or await_resume on sender-awaitable. If those public members were exposition-only, you wouldn't be able to write code to use them by name.

Even if we ignore reflection, for cw-fixed-value users could get the type from something like:

#include <type_traits>

template<class> struct Silly;

template<auto Val, class X>
struct Silly<std::constant_wrapper<Val, X>> {
  using type = decltype(Val)::type;
  auto f() { return Val.data; }
};

Making type and data exposition-only means users can't do this.

They can construct values of the type, as JA showed above, but I'm not sure we can do much about that (without heroics that I think would be unnecessary complexity).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants