Date: Fri, 3 Sep 2021 10:48:51 -0400
Greetings.
Since we can define explicitly required parameters, and implicitly
required parameters (populated with default values), I'd like to
propose a way to know the number of each provided to a function by its
caller.
This information would be available for use in two ways depending on
how it's referenced:
(1) As add-on named function parameters for use as use variables (for
output, storage, or passing as parameters to other functions). These
would be auto-added to the function's parameters by the compiler,
though invisible to the user unless an examination of the stack was
made:
(2) As compile-time definitions which allow for conditional
compilation, which would ultimately create versions of a function
based on provided counts and the subsequent reference-only logic.
-----[BEGIN: Example for type (1) ]-----
// Prototype
int func(int a, int b = 0, int c = 0);
// Use in code:
int main()
{
func(0);
func(0, 0);
func(0, 0, 0);
return 0;
}
// Body:
int func(int a, int b, int c)
{
// In theory, it would use two auto-injected compiler-added parameters:
std::cout << "Explicit count = " << __ARGS_EXPLICIT__ << std::endl;
std::cout << "Implicit count = " << __ARGS_IMPLICIT__ <<
std::endl; << std::endl;
}
The above would be used as parameters producing output with counts of:
1 explicit, 2 implicit
2 explicit, 1 implicit
3 explicit, 0 implicit
This feature would be the equivalent of translating the actual
function definition into something like this by the compiler:
int func(int __ARGS_EXPLICIT__, int __ARGS_IMPLICIT__, int a, int b =
0, int c = 0);
With auto-injected additional parameters added by the compiler like this:
func(1, 2, 0);
func(2, 1, 0, 0);
func(3, 0, 0, 0, 0);
The compiler would auto-inject those parameters. They would be
visible on the stack, but are unnamed in the prototype or body
definition. And normal optimizations would flow from the now
re-defined internal function definition expansions.
They would only be auto-injected when those macro names were
referenced in the body function.
-----[END: Example for type (1) ]-----
.
.
.
-----[BEGIN: Example for type (2) ]-----
For the conditional compilation model, this type of logic would be used:
// Prototype
int inlist(int value, int p1, int p2 = 0, int p3 = 0);
// Use in code:
int main()
{
int a = 1;
int b = 2;
int c = 3;
if (inlist(1, a, b)) std::cout << "Yes" << std::endl;
else std::cout << "No" << std::endl;
if (inlist(5, a, b, c)) std::cout << "Yes" << std::endl;
else std::cout << "No" << std::endl;
return 0;
}
// Body:
bool inlist(int value, int p1, int p2, int p3)
{
if (value == p1)
return true;
if (__ARGS_EXPLICIT__ >= __ARG_NUMBER(p2))
{
if (value == p2)
return true;
if (__ARGS_EXPLICIT__ >= __ARG_NUMBER(p3))
{
if (value == p3)
return true;
}
}
return false;
}
In the above example, the parameters are never actually used in
anything stored to memory; just flow-control logic. As such, they
become compile-time-only usages which can be conditionally compiled
creating two versions of the function, one for the three input
parameter case, and one for the four.
-----[END: Example for type (2) ]-----
When I asked about this feature on Stack Overflow, someone suggested
using std::optional:
stackoverflow dot com
/questions/68978101/visual-c-function-call-explicit-implicit-parameter-count
That works, but does not seem to be an appropriate solution due to
runtime overhead. In Microsoft's implementation, for example, the
std::optional form has three additional function calls on the func(0);
call lines, and the body of func() is referencing one call each for
has_value() in unoptimized mode. And in optimized mode, it is of the
type (1) form above, optimized inline rather than through calls into
func().
Use of std::optional is an unnecessary amount of overhead for the
developer, and the compiler, for something that is simple
known-at-compile-time information that could be auto-injected as
needed by the compiler.
After Stack Overflow's response, I proposed this extension as a
Microsoft-only extension on Microsoft's Visual Studio "suggest an
idea" system, and they suggested I propose it here:
developercommunity dot visualstudio dot com
/t/need-a-way-to-know-explicit-and-implicit-parameter/1517467
They suggested I offer it to the ISO C++ committee.
I offer it here for discussion.
Thank you.
Since we can define explicitly required parameters, and implicitly
required parameters (populated with default values), I'd like to
propose a way to know the number of each provided to a function by its
caller.
This information would be available for use in two ways depending on
how it's referenced:
(1) As add-on named function parameters for use as use variables (for
output, storage, or passing as parameters to other functions). These
would be auto-added to the function's parameters by the compiler,
though invisible to the user unless an examination of the stack was
made:
(2) As compile-time definitions which allow for conditional
compilation, which would ultimately create versions of a function
based on provided counts and the subsequent reference-only logic.
-----[BEGIN: Example for type (1) ]-----
// Prototype
int func(int a, int b = 0, int c = 0);
// Use in code:
int main()
{
func(0);
func(0, 0);
func(0, 0, 0);
return 0;
}
// Body:
int func(int a, int b, int c)
{
// In theory, it would use two auto-injected compiler-added parameters:
std::cout << "Explicit count = " << __ARGS_EXPLICIT__ << std::endl;
std::cout << "Implicit count = " << __ARGS_IMPLICIT__ <<
std::endl; << std::endl;
}
The above would be used as parameters producing output with counts of:
1 explicit, 2 implicit
2 explicit, 1 implicit
3 explicit, 0 implicit
This feature would be the equivalent of translating the actual
function definition into something like this by the compiler:
int func(int __ARGS_EXPLICIT__, int __ARGS_IMPLICIT__, int a, int b =
0, int c = 0);
With auto-injected additional parameters added by the compiler like this:
func(1, 2, 0);
func(2, 1, 0, 0);
func(3, 0, 0, 0, 0);
The compiler would auto-inject those parameters. They would be
visible on the stack, but are unnamed in the prototype or body
definition. And normal optimizations would flow from the now
re-defined internal function definition expansions.
They would only be auto-injected when those macro names were
referenced in the body function.
-----[END: Example for type (1) ]-----
.
.
.
-----[BEGIN: Example for type (2) ]-----
For the conditional compilation model, this type of logic would be used:
// Prototype
int inlist(int value, int p1, int p2 = 0, int p3 = 0);
// Use in code:
int main()
{
int a = 1;
int b = 2;
int c = 3;
if (inlist(1, a, b)) std::cout << "Yes" << std::endl;
else std::cout << "No" << std::endl;
if (inlist(5, a, b, c)) std::cout << "Yes" << std::endl;
else std::cout << "No" << std::endl;
return 0;
}
// Body:
bool inlist(int value, int p1, int p2, int p3)
{
if (value == p1)
return true;
if (__ARGS_EXPLICIT__ >= __ARG_NUMBER(p2))
{
if (value == p2)
return true;
if (__ARGS_EXPLICIT__ >= __ARG_NUMBER(p3))
{
if (value == p3)
return true;
}
}
return false;
}
In the above example, the parameters are never actually used in
anything stored to memory; just flow-control logic. As such, they
become compile-time-only usages which can be conditionally compiled
creating two versions of the function, one for the three input
parameter case, and one for the four.
-----[END: Example for type (2) ]-----
When I asked about this feature on Stack Overflow, someone suggested
using std::optional:
stackoverflow dot com
/questions/68978101/visual-c-function-call-explicit-implicit-parameter-count
That works, but does not seem to be an appropriate solution due to
runtime overhead. In Microsoft's implementation, for example, the
std::optional form has three additional function calls on the func(0);
call lines, and the body of func() is referencing one call each for
has_value() in unoptimized mode. And in optimized mode, it is of the
type (1) form above, optimized inline rather than through calls into
func().
Use of std::optional is an unnecessary amount of overhead for the
developer, and the compiler, for something that is simple
known-at-compile-time information that could be auto-injected as
needed by the compiler.
After Stack Overflow's response, I proposed this extension as a
Microsoft-only extension on Microsoft's Visual Studio "suggest an
idea" system, and they suggested I propose it here:
developercommunity dot visualstudio dot com
/t/need-a-way-to-know-explicit-and-implicit-parameter/1517467
They suggested I offer it to the ISO C++ committee.
I offer it here for discussion.
Thank you.
-- Rick C. Hodgin
Received on 2021-09-03 09:48:54