The functionality introduced here allows for reflection of concrete
functions; This enables, for instance, GUI generation, building a catalogue for
remote procedure calls, documentation generation, and signal/slot frameworks.
Like P0194, this proposal omits attributes, templates, and reification
(i.e. conversion of a meta object to the base level): all warrant a separate paper.
We would welcome a paper especially on static reflection of attributes, matching the interface-style of P0194 and this paper!
Linkage and friends will be part of a follow-up paper to P0194; they will have a combined "effect" on P0194 and this paper.

Interplay with other proposals

Most notably, this proposal relies on P0194 and the Concepts TS.

P0385 discusses use cases, rationale,
design decisions, and the future evolution of the proposed reflection
facility. It also has usage examples and replies to frequently asked questions.

Concepts and Operations

Following P0194's lead, function reflection requires a couple new concepts to restrict operations on the meta level. It builds upon the concepts introduced by P0194 and, like P0194, all declarations are inside the reflect namespace.
Some of the concepts below extend P0194's concepts. Whenever a concept A requires another concept B, the operations defined for concept B are also available for concept A, building a graph similar to an inheritance graph.

Proper wording will be provided when needed (and when P0194 has progressed through LWG, increasing to the authors' experience on wording of reflection papers); we believe that missing wording should not hinder SG7's design discussion. The wording is planned to be similar to that of P0194; specifically, it uses nested type and value entities, with the usual using declarations ..._t and ..._v.

Extending operands of reflexpr

P0194 allows certain types and variables as operands of reflexpr. This paper extends this set:

invoking reflexpr on a function name generates an OverloadSet;

invoking reflexpr on a function declaration generates a Callable that additionally satisfies other concepts defined in this paper, for instance Constructor;

invoking reflexpr on a closure type generates a Lambda;

invoking reflexpr on a parameter name generates a FunctionParameter;

invoking reflexpr on a lambda capture generates a LambdaCapture;

When invoking reflexpr on a name, the resulting OverloadSet comprises all functions (member or not) that are part of the overload set at the point of invocation of the reflexpr operator. Example:

The way to generate a Callable might seem baroque. But instead of inventing a new syntax, for instance reflexpr(foo(int,int)), or re-using the mechanism of matching the address of an overloaded function name reflexpr((void(&)(int, int))foo), we decided to use the far more common and legible approach reflexpr(void foo(int,int)), similar to the way a function definition would be introduced. This approach also works for constructors and destructors, for instance reflexpr(std::string::string()) reflects the default constructor of string.

FunctionParameter

template <class Object> concept bool FunctionParameter();

Requires Named and ScopeMember. Represents a function parameter. Unlike Variable, it does not offer a get_pointer interface. The name of a parameter is the name used in the most recent redeclaration at the point of invocation of the reflexpr operator. Its scope is the Callable declaring this FunctionParameter.

Given the lack of relevance that C++ attributes to parameter names in function declarations one might ask: "o really?!" We believe that the answer is "yes": parameter names often carry significant meaning. Examples:

To put it differently: functions without parameter names are like classes without member names. And tuple is not a replacement for classes.

Another common objection is that multiple declarations could potentially
have different parameter names ascribed. This concern is mitigated in two
ways:

Modern coding conventions have the declarations for a particular
function showing up in exactly one header file.

Modern coding conventions discourage the use of different argument
names between function declarations (in a header) and function
definitions (in a '.cpp' file). Dedicated compiler warnings exist to
protecte against this case.

Callable

template <class Object> concept bool Callable();

Requires Named, ScopeMember and Scope. Represents a function or lambda, including operators, constructors and destructors - i.e. anything this paper is dealing with.

Operations

template <Callable> struct get_parameters;

Returns an ObjectSequence of FunctionParameters of the reflected Callable.

Returns whether the function was declared as constexpr or noexcept, respectively.

template <Callable> struct is_inline;

Returns whether the function is an inline function. With struct X{ inline void f(); void g() {} }, is_inline is true for both f and g.

template <Callable> struct is_deleted;

Returns whether the function was defined as = delete before the invocation of reflexpr.

OverloadSet

template <class Object> concept bool OverloadSet();

Requires Named. Represents a sequence of overloads with a given name. Example: reflexpr(sin) returns a type that satisfies OverloadSet.

Operations

template <OverloadSet> struct get_overloads;

Returns an ObjectSequence of Callables of a given name, e.g. get_overloads_t<reflexpr(sin)> returns a ObjectSequence of all sin overloads.
This includes template specializations at the point of invocation of the reflexpr operator. The order of the elements is the order of declaration, ignoring possible redeclarations.

Function

template <class Object> concept bool Function();

Requires Callable and Typed. Represents a function or lambda, excluding constructors and destructors.

Operations

template <Function> struct get_pointer;

Returns a pointer to the function. This is a pointer-to-member for non-static member functions, and a function pointer otherwise. It is ill-formed to invoke this for deleted functions. Example: auto p_sin = get_pointer_v<reflexpr(double sin(double))> holds the address of sin(double).

RecordMemberFunction

template <class Object> concept bool RecordMemberFunction();

Requires RecordMember and Function. Represents a member function, excluding constructors and destructors.

Returns whether the function is declared as override or final, respectively.

SpecialMemberFunction

template <class Object> concept bool SpecialMemberFunction();

Requires RecordMember. Represents a special member function.

Operations

template <SpecialMemberFunction> struct is_implicitly_declared;

Returns whether the special member function is known to be implicitly declared at the point of invocation of reflexpr.

template <SpecialMemberFunction> struct is_defaulted;

Returns whether the function is defined as = default before the invocation of reflexpr, independently of whether the special member function is implicitly or explicitly declared.

Constructor

template <class Object> concept bool Constructor();

Requires Callable and RecordMember. Represents a constructor. The base name of the constructor is the base name of the constructor's class. Even though the standard explicitly says that constructors do not have a name, for usability purposes (e.g. generating messages), having them state the class name is a usability improvement.

Some instances of Constructor might also satisfy SpecialMemberFunction.

Operations

template <Constructor> struct is_explicit;

Returns whether the constructor is known to be declared as explicit.

Destructor

template <class Object> concept bool Destructor();

Requires Callable, SpecialMemberFunction and RecordMember. Represents a destructor. The base name is the base name if the destructor's class, prefixed with '~'.

Returns an ObjectSequence of OverloadSets representing a class's public member functions (for get_public_member_functions), member functions accessible from the point of invocation of reflexpr (for get_accessible_member_functions) and all member functions, irrespective of their accessibility (for get_member_functions).