This is an archive of the discontinued LLVM Phabricator instance.

[libcxx] adds concepts `std::invocable` and `std::regular_invocable`
ClosedPublic

Authored by cjdb on Feb 7 2021, 9:10 PM.

Details

Summary

Implements parts of:

  • P0898R3 Standard Library Concepts
  • P1754 Rename concepts to standard_case for C++20, while we still can

Diff Detail

Event Timeline

cjdb requested review of this revision.Feb 7 2021, 9:10 PM
cjdb created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptFeb 7 2021, 9:10 PM
Herald added a reviewer: Restricted Project. · View Herald Transcript
Mordante accepted this revision.Feb 9 2021, 9:47 AM

Except for the build issue, LGTM!

libcxx/test/std/concepts/callable/invocable.pass.cpp
110 ↗(On Diff #322022)

Can you initialize it with something different, this seems to cause a build failure when the platform has no random device.

ldionne added inline comments.Feb 9 2021, 3:36 PM
libcxx/include/concepts
211

The Standard seems to say that we should call invoke unqualified: http://eel.is/c++draft/concept.invocable#concept:invocable.

This seems a bit weird to me - I assume I'm missing some context or mis-reading the paragraph prior to the concept definition?

CaseyCarter added inline comments.Feb 9 2021, 4:32 PM
libcxx/include/concepts
211

I suspect you're forgetting http://eel.is/c++draft/contents#3 "meow really means ::std::meow". Please don't ask me why the Standard always says std::move / std::forward or my head will explode.

Source comment: there's a weird mixture of _VSTD:: and std:: here - is that intended? (I have a vague notion that std:: is used only for exceptions that are stable across ABIs or something?)

cjdb updated this revision to Diff 322561.Feb 9 2021, 6:11 PM

fixes build issue and replaces std:: with _VSTD::

cjdb updated this revision to Diff 322563.Feb 9 2021, 6:13 PM
cjdb marked 2 inline comments as done.

adds new lines to EOFs

ldionne accepted this revision.Feb 10 2021, 9:03 AM
ldionne added inline comments.
libcxx/include/concepts
211

Oh, thanks.

The difference between _VSTD:: and std:: is unclear to me as well, to be entirely honest. Eric tried removing _VSTD:: altogether at some point and the attempt was meant with push back by some people who use the _VSTD macro to completely different ends.

I think you might be mistaking this with the fact that we define exception types outside of the __1 inline namespace so that they mangle the same as exceptions from libstdc++ (when interop between the two was necessary).

This revision is now accepted and ready to land.Feb 10 2021, 9:03 AM
cjdb marked an inline comment as not done.Feb 10 2021, 11:07 AM
cjdb added inline comments.
libcxx/include/concepts
214–216

The difference between invocable and regular_invocable is purely semantic. Do we want do add any sort of documentation here to indicate as much?

libcxx/test/std/concepts/callable/invocable.pass.cpp
110 ↗(On Diff #322022)

Yes, but I'm going to open a bug, because I think

Quuxplusone added inline comments.
libcxx/include/concepts
211

FWIW, I think the difference is purely that _VSTD:: is std::__1::. This is significant in SFINAE-related-mangling contexts, e.g. https://godbolt.org/z/xGbTG7 (which GCC gets wrong anyway).

When I did my big _VSTD::-normalization patch series (mainly focused on eliminating unwanted ADL but also normalizing what was already there), the only places using std:: were std::type_info and std::nothrow_t, both (I assumed) for ABI reasons.

My personal interpretation of libc++ style is that we use std:: only in weird historical ABI corner cases; _VSTD:: for things that would trigger ADL (all function calls taking any parameters, but notably not declval); and for everything else we use no qualification. E.g. in this file _VSTD::is_constructible_v should be just is_constructible_v; and in <chrono> I see four accidental instances of std::numeric_limits which should be just numeric_limits.

Teeny nit: equality-preserving should be hyphenated.

libcxx/test/std/concepts/callable/invocable.compile.pass.cpp
26

spurious ;
FWIW, I'd prefer indenting as

template<class F, class... Args> requires std::invocable<F, Args...>
constexpr void ModelsInvocable(F, Args&&...) noexcept { }

or

template<class F, class... Args>
    requires std::invocable<F, Args...>
constexpr void
ModelsInvocable(F, Args&&...) noexcept { }
114

Incidentally, blech. ;) What's the default here — std::uniform_int_distribution<int>?

libcxx/test/std/concepts/callable/regularinvocable.compile.pass.cpp
115

I would suggest commenting this back in, since a conforming implementation must accept it.
Ideally diff regularinvocable.compile.pass.cpp invocable.compile.pass.cpp should produce only a single line of differences — the name of the constraint.
I might also add a test that verifies that invocable and regular_invocable subsume each other (i.e., a conforming program cannot rely on regular_invocable to be a more specialized constraint than plain invocable).

libcxx/include/concepts
138

Could we omit this line, and use _VSTD::__invoke (from <type_traits>) below instead of _VSTD::invoke (from <functional>)?
Alternatively, could someone add to their to-do list "move std::invoke into <type_traits> or something" so that <concepts> doesn't have to pull in all the <functional> stuff?