Discussion:
[std-proposals] Parametric Expression
Jason Rice
2018-08-30 16:42:55 UTC
Permalink
Here is a write up for a language feature that I would like to have
considered:

https://gist.github.com/ricejasonf/84c11ac6bb093c1ea8c380a9a466d8cb

I'm attempting to implement it in Clang, but I would like to get some early
feedback.

I've already received some feedback from Louis Dionne and he encouraged me
to post it here.


Thanks!



# Parametric Expression

The primary purpose here is to improve compile-time performance by
providing a tool that augments existing
metaprogramming features in C++. It involves the transformation of
expressions.

Essentially this feature is meant to combine the power of function
templates with the performance of type
aliases. Function templates as we have them now are loaded with features
such as overloading, constraints,
type deduction, SFINAE, ect.. When called not only do we get an expensive
template instantiation but also
potentially large symbols and extraneous code generation all for functions
we wouldn't call otherwise
unless we expected the optimizer to inline them out anyways. With this tool
we want to give programmers
the ability to allow this inlining at an earlier stage, but the solution is
elegant enough to provide a
few additional bonus features.

Consider the following declaration syntax:

```cpp
using add(auto a, auto b) {
return a + b;
}
```

Here is a function-like declaration where the domain and codomain are
expressions.

Invoking it merely transforms the expression in the context of the site of
invocation.

```cpp
int main() {
return add(40, 2);
}

// the same as

int main() {
return 40 + 2;
}
```

This ability to transform expressions has the same power as type aliases,
but here we can work with
constructs that have run-time effects as seen in Fusion/Hana style
metaprogramming. Additionally,
since this is a language feature, we could pontentially see the same
compile-time performance that
Kvasir.Mpl has without the difficult continuation interface (and it works
on expressions!).


## Additional Bonus Features

Since the expressions maintain the context of the site of invocation we
also get constexpr parameters.

```cpp
using to_integral_constant(auto x) {
return std::integral_constant<int, x>{};
}

int main() {
constexpr int x = 0;
static_assert(std::is_same_v<std::integral_constant<int, 0>,
decltype(to_integral_constant(x)));
}
```

We also get arrays and string literals that do not decay.

```cpp
using id(auto x) {
return x;
}

int main() {
char const* foo = id("foo");
}

// the same as

int main() {
char const* foo = "foo";
}
```

To top it off, we also get a clean syntax for Perfect Forwarding

* This assumes that the input expression casts to an rvalue
* See the rules below for information on how value categories are handled

```cpp
template <typename F, typename X, typename Y>
decltype(auto) flip(F&& f, X&& x, y&& y) {
return std::forward<F>(f)(std::forward<Y>(y), std::forward<X>(x));
}

// becomes

using flip(auto f, auto x, auto y) {
return f(y, x);
}
```

## As a Member of a Class

Parametric expressions can be used as a member in conjunction with operator
overloading to create an
invocable object:

```cpp
struct id_fn {
using operator()(auto x) {
return x;
}
};

id_fn{}(42);

static_assert(std::is_invocable<id_fn, int>::value);
```


## The Rules

1. The input parameter list may contain only one parameter pack in any
position.
* This is afforded since we don't do type deduction

2. The input parameters may be unexpanded parameter packs.
* This adds a bit more power for working with lists.
* see [Multicategory][1]

3. The output expression must NOT contain any unexpanded parameter packs
* This would prevent pack expansion ambiguity at the call site

4. Input parameter type specifiers must be completely unconstrained and
never have type qualifiers.
* We could possibly apply constraints to the type in the future via
Concepts

5. The definition is a compound statement where the final statement must
either be a return statement
or a constexpr if/else statement where each branch follows this same
rule.
* There can be only one return statement which yields the output
expression

6. Recursion is not allowed
* Not sure if recursion would be feasible, but we could at least use
Odin Holmes' recursive
alias pattern

7. Input parameters are expression aliases which follow different rules
with regard to the evaluated
type's value category and reference type:
1. Prvalue constant-expressions are simply pasted wherever it is used
in the definition.
* This affords constexpr parameters and literals
2. Unexpanded parameter packs are pasted where the parameter is used in
the expression.
* Again note that they must be expanded wherever they are used in
the definition
2. Everything else is bound to an lvalue reference within the compound
statement implicitly.
3. Expressions evaluating to an rvalue have the last evaluated use in
the definition cast to an
rvalue.
* The compiler should be able to determine this internally even for
cases where order of
evaluation is unspecified.
* This also implies that this could be used to detect order of
evaluation of a function call.
* This is similar to how Rust handles implicit moves!

8. Input expressions that are not constant-expressions will be evaluated
immediately from left to right
as specified in the parameter list.
* Note that unexpanded packs are not included in this

9. The output is a generated compound statement evaluated as an expression
that is specified using
the return statement in the definition body of the parametric expression.


I see this as potentially having a huge impact on the ability to implement
ranges, expression templates,
metaprogramming libraries, and my own pet case of nesting continuations for
various purposes. It would be
really cool to get this in C++20 if it is not too late.


Thanks for looking at this!

Jason Rice

[1]: https://en.wikipedia.org/wiki/Multicategory
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95ae303b-329c-4121-aa5f-69edf040d5b5%40isocpp.org.
Richard Smith
2018-08-30 22:01:18 UTC
Permalink
I'd worry a little about such a facility being overused where people really
just want a function with a strong "inline this please" hint (but then
again, any feature can be misused). But this seems like an interesting way
to address a collection of cases where people currently use macros.

The paper would benefit from a collection of realistic usage examples.

"Expressions evaluating to an rvalue have the last evaluated use in the
definition cast to an rvalue.
The compiler should be able to determine this internally even for cases
where order of evaluation is unspecified."

Can the body of the alias contain control flow constructs? I don't think
the compiler can determine this in general. It's also unfortunate that you
don't support (guaranteed) copy elision for rvalue parameters under any
circumstances.
Post by Jason Rice
Here is a write up for a language feature that I would like to have
https://gist.github.com/ricejasonf/84c11ac6bb093c1ea8c380a9a466d8cb
I'm attempting to implement it in Clang, but I would like to get some
early feedback.
I've already received some feedback from Louis Dionne and he encouraged me
to post it here.
Thanks!
# Parametric Expression
The primary purpose here is to improve compile-time performance by
providing a tool that augments existing
metaprogramming features in C++. It involves the transformation of
expressions.
Essentially this feature is meant to combine the power of function
templates with the performance of type
aliases. Function templates as we have them now are loaded with features
such as overloading, constraints,
type deduction, SFINAE, ect.. When called not only do we get an expensive
template instantiation but also
potentially large symbols and extraneous code generation all for functions
we wouldn't call otherwise
unless we expected the optimizer to inline them out anyways. With this
tool we want to give programmers
the ability to allow this inlining at an earlier stage, but the solution
is elegant enough to provide a
few additional bonus features.
```cpp
using add(auto a, auto b) {
return a + b;
}
```
Here is a function-like declaration where the domain and codomain are
expressions.
Invoking it merely transforms the expression in the context of the site of
invocation.
```cpp
int main() {
return add(40, 2);
}
// the same as
int main() {
return 40 + 2;
}
```
This ability to transform expressions has the same power as type aliases,
but here we can work with
constructs that have run-time effects as seen in Fusion/Hana style
metaprogramming. Additionally,
since this is a language feature, we could pontentially see the same
compile-time performance that
Kvasir.Mpl has without the difficult continuation interface (and it works
on expressions!).
## Additional Bonus Features
Since the expressions maintain the context of the site of invocation we
also get constexpr parameters.
```cpp
using to_integral_constant(auto x) {
return std::integral_constant<int, x>{};
}
int main() {
constexpr int x = 0;
static_assert(std::is_same_v<std::integral_constant<int, 0>,
decltype(to_integral_constant(x)));
}
```
We also get arrays and string literals that do not decay.
```cpp
using id(auto x) {
return x;
}
int main() {
char const* foo = id("foo");
}
// the same as
int main() {
char const* foo = "foo";
}
```
To top it off, we also get a clean syntax for Perfect Forwarding
* This assumes that the input expression casts to an rvalue
* See the rules below for information on how value categories are handled
```cpp
template <typename F, typename X, typename Y>
decltype(auto) flip(F&& f, X&& x, y&& y) {
return std::forward<F>(f)(std::forward<Y>(y), std::forward<X>(x));
}
// becomes
using flip(auto f, auto x, auto y) {
return f(y, x);
}
```
## As a Member of a Class
Parametric expressions can be used as a member in conjunction with
operator overloading to create an
```cpp
struct id_fn {
using operator()(auto x) {
return x;
}
};
id_fn{}(42);
static_assert(std::is_invocable<id_fn, int>::value);
```
## The Rules
1. The input parameter list may contain only one parameter pack in any
position.
* This is afforded since we don't do type deduction
2. The input parameters may be unexpanded parameter packs.
* This adds a bit more power for working with lists.
* see [Multicategory][1]
3. The output expression must NOT contain any unexpanded parameter packs
* This would prevent pack expansion ambiguity at the call site
4. Input parameter type specifiers must be completely unconstrained and
never have type qualifiers.
* We could possibly apply constraints to the type in the future via
Concepts
5. The definition is a compound statement where the final statement must
either be a return statement
or a constexpr if/else statement where each branch follows this same
rule.
* There can be only one return statement which yields the output
expression
6. Recursion is not allowed
* Not sure if recursion would be feasible, but we could at least use
Odin Holmes' recursive
alias pattern
7. Input parameters are expression aliases which follow different rules
with regard to the evaluated
1. Prvalue constant-expressions are simply pasted wherever it is used
in the definition.
* This affords constexpr parameters and literals
2. Unexpanded parameter packs are pasted where the parameter is used
in the expression.
* Again note that they must be expanded wherever they are used in
the definition
2. Everything else is bound to an lvalue reference within the compound
statement implicitly.
3. Expressions evaluating to an rvalue have the last evaluated use in
the definition cast to an
rvalue.
* The compiler should be able to determine this internally even
for cases where order of
evaluation is unspecified.
* This also implies that this could be used to detect order of
evaluation of a function call.
* This is similar to how Rust handles implicit moves!
8. Input expressions that are not constant-expressions will be evaluated
immediately from left to right
as specified in the parameter list.
* Note that unexpanded packs are not included in this
9. The output is a generated compound statement evaluated as an expression
that is specified using
the return statement in the definition body of the parametric expression.
I see this as potentially having a huge impact on the ability to implement
ranges, expression templates,
metaprogramming libraries, and my own pet case of nesting continuations
for various purposes. It would be
really cool to get this in C++20 if it is not too late.
Thanks for looking at this!
Jason Rice
[1]: https://en.wikipedia.org/wiki/Multicategory
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95ae303b-329c-4121-aa5f-69edf040d5b5%40isocpp.org
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95ae303b-329c-4121-aa5f-69edf040d5b5%40isocpp.org?utm_medium=email&utm_source=footer>
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAOfiQqknXM3%3D8x4wmGGboSYh%3DtuMfrUU2MuxVM0XtEur95LhgA%40mail.gmail.com.
Jason Rice
2018-08-30 23:21:16 UTC
Permalink
Post by Richard Smith
Can the body of the alias contain control flow constructs?
If you mean like if/else statements then I would say yes along with side
effects and what not. It generates a compound statement that yields as an
expression determined by the return statement.

I don't think the compiler can determine this in general. It's also
Post by Richard Smith
unfortunate that you don't support (guaranteed) copy elision for rvalue
parameters under any circumstances.
The parameters are aliases to expressions so there isn't any copying going
on so I don't know that specifying copy elision is necessary.

In the case where the expression param is used only once we could just
paste the expression, but that would definitely make the order of
evaluation thing right out. I'm fine with that.

For the case where the param is used multiple times we substitute with a
reference to the result of the expression by generating a statement within
the compound statement.

I'm still thinking that implicit recast to rvalue is possible except in
cases where it is used that the order of evaluation is undefined. If that
is too difficult, we can rip it out as it is tertiary anyways.

I will work on getting some realistic usage examples up. Thanks!
Post by Richard Smith
I'd worry a little about such a facility being overused where people
really just want a function with a strong "inline this please" hint (but
then again, any feature can be misused). But this seems like an interesting
way to address a collection of cases where people currently use macros.
The paper would benefit from a collection of realistic usage examples.
"Expressions evaluating to an rvalue have the last evaluated use in the
definition cast to an rvalue.
The compiler should be able to determine this internally even for cases
where order of evaluation is unspecified."
Can the body of the alias contain control flow constructs? I don't think
the compiler can determine this in general. It's also unfortunate that you
don't support (guaranteed) copy elision for rvalue parameters under any
circumstances.
Post by Jason Rice
Here is a write up for a language feature that I would like to have
https://gist.github.com/ricejasonf/84c11ac6bb093c1ea8c380a9a466d8cb
I'm attempting to implement it in Clang, but I would like to get some
early feedback.
I've already received some feedback from Louis Dionne and he encouraged
me to post it here.
Thanks!
# Parametric Expression
The primary purpose here is to improve compile-time performance by
providing a tool that augments existing
metaprogramming features in C++. It involves the transformation of
expressions.
Essentially this feature is meant to combine the power of function
templates with the performance of type
aliases. Function templates as we have them now are loaded with features
such as overloading, constraints,
type deduction, SFINAE, ect.. When called not only do we get an expensive
template instantiation but also
potentially large symbols and extraneous code generation all for
functions we wouldn't call otherwise
unless we expected the optimizer to inline them out anyways. With this
tool we want to give programmers
the ability to allow this inlining at an earlier stage, but the solution
is elegant enough to provide a
few additional bonus features.
```cpp
using add(auto a, auto b) {
return a + b;
}
```
Here is a function-like declaration where the domain and codomain are
expressions.
Invoking it merely transforms the expression in the context of the site
of invocation.
```cpp
int main() {
return add(40, 2);
}
// the same as
int main() {
return 40 + 2;
}
```
This ability to transform expressions has the same power as type aliases,
but here we can work with
constructs that have run-time effects as seen in Fusion/Hana style
metaprogramming. Additionally,
since this is a language feature, we could pontentially see the same
compile-time performance that
Kvasir.Mpl has without the difficult continuation interface (and it works
on expressions!).
## Additional Bonus Features
Since the expressions maintain the context of the site of invocation we
also get constexpr parameters.
```cpp
using to_integral_constant(auto x) {
return std::integral_constant<int, x>{};
}
int main() {
constexpr int x = 0;
static_assert(std::is_same_v<std::integral_constant<int, 0>,
decltype(to_integral_constant(x)));
}
```
We also get arrays and string literals that do not decay.
```cpp
using id(auto x) {
return x;
}
int main() {
char const* foo = id("foo");
}
// the same as
int main() {
char const* foo = "foo";
}
```
To top it off, we also get a clean syntax for Perfect Forwarding
* This assumes that the input expression casts to an rvalue
* See the rules below for information on how value categories are handled
```cpp
template <typename F, typename X, typename Y>
decltype(auto) flip(F&& f, X&& x, y&& y) {
return std::forward<F>(f)(std::forward<Y>(y), std::forward<X>(x));
}
// becomes
using flip(auto f, auto x, auto y) {
return f(y, x);
}
```
## As a Member of a Class
Parametric expressions can be used as a member in conjunction with
operator overloading to create an
```cpp
struct id_fn {
using operator()(auto x) {
return x;
}
};
id_fn{}(42);
static_assert(std::is_invocable<id_fn, int>::value);
```
## The Rules
1. The input parameter list may contain only one parameter pack in any
position.
* This is afforded since we don't do type deduction
2. The input parameters may be unexpanded parameter packs.
* This adds a bit more power for working with lists.
* see [Multicategory][1]
3. The output expression must NOT contain any unexpanded parameter packs
* This would prevent pack expansion ambiguity at the call site
4. Input parameter type specifiers must be completely unconstrained and
never have type qualifiers.
* We could possibly apply constraints to the type in the future via
Concepts
5. The definition is a compound statement where the final statement must
either be a return statement
or a constexpr if/else statement where each branch follows this same
rule.
* There can be only one return statement which yields the output
expression
6. Recursion is not allowed
* Not sure if recursion would be feasible, but we could at least use
Odin Holmes' recursive
alias pattern
7. Input parameters are expression aliases which follow different rules
with regard to the evaluated
1. Prvalue constant-expressions are simply pasted wherever it is used
in the definition.
* This affords constexpr parameters and literals
2. Unexpanded parameter packs are pasted where the parameter is used
in the expression.
* Again note that they must be expanded wherever they are used in
the definition
2. Everything else is bound to an lvalue reference within the
compound statement implicitly.
3. Expressions evaluating to an rvalue have the last evaluated use in
the definition cast to an
rvalue.
* The compiler should be able to determine this internally even
for cases where order of
evaluation is unspecified.
* This also implies that this could be used to detect order of
evaluation of a function call.
* This is similar to how Rust handles implicit moves!
8. Input expressions that are not constant-expressions will be evaluated
immediately from left to right
as specified in the parameter list.
* Note that unexpanded packs are not included in this
9. The output is a generated compound statement evaluated as an
expression that is specified using
the return statement in the definition body of the parametric expression.
I see this as potentially having a huge impact on the ability to
implement ranges, expression templates,
metaprogramming libraries, and my own pet case of nesting continuations
for various purposes. It would be
really cool to get this in C++20 if it is not too late.
Thanks for looking at this!
Jason Rice
[1]: https://en.wikipedia.org/wiki/Multicategory
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95ae303b-329c-4121-aa5f-69edf040d5b5%40isocpp.org
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95ae303b-329c-4121-aa5f-69edf040d5b5%40isocpp.org?utm_medium=email&utm_source=footer>
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/06d2d0a6-dcf0-4365-8f64-bc4603804a58%40isocpp.org.
Jason Rice
2018-08-30 23:34:49 UTC
Permalink
Here is what I have so far for implementation:
https://github.com/ricejasonf/clang/commits/f_alias

If you or anyone can offer any guidance or mentorship on this it would be
greatly appreciated.
Post by Richard Smith
I'd worry a little about such a facility being overused where people
really just want a function with a strong "inline this please" hint (but
then again, any feature can be misused). But this seems like an interesting
way to address a collection of cases where people currently use macros.
The paper would benefit from a collection of realistic usage examples.
"Expressions evaluating to an rvalue have the last evaluated use in the
definition cast to an rvalue.
The compiler should be able to determine this internally even for cases
where order of evaluation is unspecified."
Can the body of the alias contain control flow constructs? I don't think
the compiler can determine this in general. It's also unfortunate that you
don't support (guaranteed) copy elision for rvalue parameters under any
circumstances.
Post by Jason Rice
Here is a write up for a language feature that I would like to have
https://gist.github.com/ricejasonf/84c11ac6bb093c1ea8c380a9a466d8cb
I'm attempting to implement it in Clang, but I would like to get some
early feedback.
I've already received some feedback from Louis Dionne and he encouraged
me to post it here.
Thanks!
# Parametric Expression
The primary purpose here is to improve compile-time performance by
providing a tool that augments existing
metaprogramming features in C++. It involves the transformation of
expressions.
Essentially this feature is meant to combine the power of function
templates with the performance of type
aliases. Function templates as we have them now are loaded with features
such as overloading, constraints,
type deduction, SFINAE, ect.. When called not only do we get an expensive
template instantiation but also
potentially large symbols and extraneous code generation all for
functions we wouldn't call otherwise
unless we expected the optimizer to inline them out anyways. With this
tool we want to give programmers
the ability to allow this inlining at an earlier stage, but the solution
is elegant enough to provide a
few additional bonus features.
```cpp
using add(auto a, auto b) {
return a + b;
}
```
Here is a function-like declaration where the domain and codomain are
expressions.
Invoking it merely transforms the expression in the context of the site
of invocation.
```cpp
int main() {
return add(40, 2);
}
// the same as
int main() {
return 40 + 2;
}
```
This ability to transform expressions has the same power as type aliases,
but here we can work with
constructs that have run-time effects as seen in Fusion/Hana style
metaprogramming. Additionally,
since this is a language feature, we could pontentially see the same
compile-time performance that
Kvasir.Mpl has without the difficult continuation interface (and it works
on expressions!).
## Additional Bonus Features
Since the expressions maintain the context of the site of invocation we
also get constexpr parameters.
```cpp
using to_integral_constant(auto x) {
return std::integral_constant<int, x>{};
}
int main() {
constexpr int x = 0;
static_assert(std::is_same_v<std::integral_constant<int, 0>,
decltype(to_integral_constant(x)));
}
```
We also get arrays and string literals that do not decay.
```cpp
using id(auto x) {
return x;
}
int main() {
char const* foo = id("foo");
}
// the same as
int main() {
char const* foo = "foo";
}
```
To top it off, we also get a clean syntax for Perfect Forwarding
* This assumes that the input expression casts to an rvalue
* See the rules below for information on how value categories are handled
```cpp
template <typename F, typename X, typename Y>
decltype(auto) flip(F&& f, X&& x, y&& y) {
return std::forward<F>(f)(std::forward<Y>(y), std::forward<X>(x));
}
// becomes
using flip(auto f, auto x, auto y) {
return f(y, x);
}
```
## As a Member of a Class
Parametric expressions can be used as a member in conjunction with
operator overloading to create an
```cpp
struct id_fn {
using operator()(auto x) {
return x;
}
};
id_fn{}(42);
static_assert(std::is_invocable<id_fn, int>::value);
```
## The Rules
1. The input parameter list may contain only one parameter pack in any
position.
* This is afforded since we don't do type deduction
2. The input parameters may be unexpanded parameter packs.
* This adds a bit more power for working with lists.
* see [Multicategory][1]
3. The output expression must NOT contain any unexpanded parameter packs
* This would prevent pack expansion ambiguity at the call site
4. Input parameter type specifiers must be completely unconstrained and
never have type qualifiers.
* We could possibly apply constraints to the type in the future via
Concepts
5. The definition is a compound statement where the final statement must
either be a return statement
or a constexpr if/else statement where each branch follows this same
rule.
* There can be only one return statement which yields the output
expression
6. Recursion is not allowed
* Not sure if recursion would be feasible, but we could at least use
Odin Holmes' recursive
alias pattern
7. Input parameters are expression aliases which follow different rules
with regard to the evaluated
1. Prvalue constant-expressions are simply pasted wherever it is used
in the definition.
* This affords constexpr parameters and literals
2. Unexpanded parameter packs are pasted where the parameter is used
in the expression.
* Again note that they must be expanded wherever they are used in
the definition
2. Everything else is bound to an lvalue reference within the
compound statement implicitly.
3. Expressions evaluating to an rvalue have the last evaluated use in
the definition cast to an
rvalue.
* The compiler should be able to determine this internally even
for cases where order of
evaluation is unspecified.
* This also implies that this could be used to detect order of
evaluation of a function call.
* This is similar to how Rust handles implicit moves!
8. Input expressions that are not constant-expressions will be evaluated
immediately from left to right
as specified in the parameter list.
* Note that unexpanded packs are not included in this
9. The output is a generated compound statement evaluated as an
expression that is specified using
the return statement in the definition body of the parametric expression.
I see this as potentially having a huge impact on the ability to
implement ranges, expression templates,
metaprogramming libraries, and my own pet case of nesting continuations
for various purposes. It would be
really cool to get this in C++20 if it is not too late.
Thanks for looking at this!
Jason Rice
[1]: https://en.wikipedia.org/wiki/Multicategory
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95ae303b-329c-4121-aa5f-69edf040d5b5%40isocpp.org
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/95ae303b-329c-4121-aa5f-69edf040d5b5%40isocpp.org?utm_medium=email&utm_source=footer>
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/1254f645-d799-42d3-af1d-90c1b24e5ee7%40isocpp.org.
s***@gmail.com
2018-08-31 16:17:44 UTC
Permalink
On the abuse of inlining I believe that implementations could create hidden fuctions if inlining is too colstly as long as it doesn't impact semantics.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/80215dcb-875f-42c0-8f7f-e8030c2145e7%40isocpp.org.
Jason Rice
2018-09-10 20:13:53 UTC
Permalink
The feedback on this so far has been greatly appreciated.

I added a couple of examples and refactored the rules to address some of
the concerns that were brought up.

https://gist.github.com/ricejasonf/84c11ac6bb093c1ea8c380a9a466d8cb
Post by s***@gmail.com
On the abuse of inlining I believe that implementations could create
hidden fuctions if inlining is too colstly as long as it doesn't impact
semantics.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ab3a09d5-6c45-43d1-9666-9749dbf7051c%40isocpp.org.
Miguel Ojeda
2018-09-12 16:26:16 UTC
Permalink
Hi Jason,
Post by Jason Rice
The feedback on this so far has been greatly appreciated.
I added a couple of examples and refactored the rules to address some of the
concerns that were brought up.
https://gist.github.com/ricejasonf/84c11ac6bb093c1ea8c380a9a466d8cb
We had a quick discussion a few months ago [1] on how to implement
something that would allow you to write things like:

x = x || new int;

In other words, an operator|| with short-circuit semantics. There were
suggestions on changing the language (the topic starter), on
standardizing language extensions (the binary ?: GNU operator) and on
doing some tricks with a macro and a lambda, e.g:

#define LAZY(x) [](){ return (x); }

template <typename T, typename E>
T operator||(T p, E e)
{
if (p)
return p;
return e();
}

x = x || LAZY(new int);

Half-jokingly, I suggested working with expressions instead would look
very nice and would allow to implement these things directly in the
language, e.g.:

template <typename T, expression E>
T operator||(T p, E e)
{
if (p)
return p;
return e;
}

x = x || new int;

How would your add() example look using this "expression" syntax?
Maybe something like:

template <typename T, expression E>
E add(T a, T b)
{
return a + b;
}

Now, the other way around, let's take a look at the operator||()
example using your "using" syntax:

using operator||(auto p, ???) {
if (p)
return p;
return ???;
}

Almost there! I am sure you are seeing what I am getting at here. If
we are going to get almost-macro-like entities, we are basically
talking about manipulating (or rather, being able to express)
expressions. Your approach, if I interpreted it correctly, allows to
return a C++ expression given a function-like call, but does not allow
to pick expressions themselves as parameters --- which would allow to
implement things like those short-circuit operators and replace even
more macros.

We could implement operators already existing in the language in terms
of the language itself:

using myOwnTernary(auto c, expression t, expression f) {
if (c)
return t;
return f;
}

// foo() only called if the condition is true
int x = myOwnTernary(something, 1, foo());

Inexpensive logging is another place where it is useful (to avoid
evaluating parameters, e.g. Boost's LOG_WARNING):

using logWarning(expression... es) {
if (level >= warning)
doLog(es...);
}

Think about it!

Cheers,
Miguel

[1] https://groups.google.com/a/isocpp.org/d/msg/std-proposals/jB5TIcRZeic/qZqxtxSDAQAJ
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CANiq72k7K%2BU2Gtjhe8rFk5TjdW8aQLyDO0Qw4pop3G1ftJ-OAQ%40mail.gmail.com.
Jason Rice
2018-09-12 18:05:34 UTC
Permalink
Perhaps we should consider adding provisions for those specific operators
(ie operator&& operator||) because that would be very useful. I can only
imagine they lose their short-circuiting properties when overloaded because
of the legacy of normal functions.

All of the parameters to this "using" function are expressions, but in
cases where that would be a pitfall, we are substituting it with an lvalue
to the result of the expression. This is tentative, and some have suggested
it behave more like a function and always treat the params as lvalues. For
me personally, the issue is tertiary to having something like a function
that doesn't produce a type. (constexpr params are high up there too though)

As it stands now this feature guarantees the operands are evaluated exactly
once, but I will consider adding provisional items to address short circuit
evaluation for those specific operators. (somehow)

A special class of parameter that would allow the omission of evaluation is
something that is possible to add separately so I will leave it out for
this initial feature request.

Thanks!
Post by Miguel Ojeda
Hi Jason,
Post by Jason Rice
The feedback on this so far has been greatly appreciated.
I added a couple of examples and refactored the rules to address some of
the
Post by Jason Rice
concerns that were brought up.
https://gist.github.com/ricejasonf/84c11ac6bb093c1ea8c380a9a466d8cb
We had a quick discussion a few months ago [1] on how to implement
x = x || new int;
In other words, an operator|| with short-circuit semantics. There were
suggestions on changing the language (the topic starter), on
standardizing language extensions (the binary ?: GNU operator) and on
#define LAZY(x) [](){ return (x); }
template <typename T, typename E>
T operator||(T p, E e)
{
if (p)
return p;
return e();
}
x = x || LAZY(new int);
Half-jokingly, I suggested working with expressions instead would look
very nice and would allow to implement these things directly in the
template <typename T, expression E>
T operator||(T p, E e)
{
if (p)
return p;
return e;
}
x = x || new int;
How would your add() example look using this "expression" syntax?
template <typename T, expression E>
E add(T a, T b)
{
return a + b;
}
Now, the other way around, let's take a look at the operator||()
using operator||(auto p, ???) {
if (p)
return p;
return ???;
}
Almost there! I am sure you are seeing what I am getting at here. If
we are going to get almost-macro-like entities, we are basically
talking about manipulating (or rather, being able to express)
expressions. Your approach, if I interpreted it correctly, allows to
return a C++ expression given a function-like call, but does not allow
to pick expressions themselves as parameters --- which would allow to
implement things like those short-circuit operators and replace even
more macros.
We could implement operators already existing in the language in terms
using myOwnTernary(auto c, expression t, expression f) {
if (c)
return t;
return f;
}
// foo() only called if the condition is true
int x = myOwnTernary(something, 1, foo());
Inexpensive logging is another place where it is useful (to avoid
using logWarning(expression... es) {
if (level >= warning)
doLog(es...);
}
Think about it!
Cheers,
Miguel
[1]
https://groups.google.com/a/isocpp.org/d/msg/std-proposals/jB5TIcRZeic/qZqxtxSDAQAJ
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/b0b395d6-a221-41a7-8ec6-08b83576cda0%40isocpp.org.
Miguel Ojeda
2018-09-12 20:03:15 UTC
Permalink
Hi Jason,
Post by Jason Rice
Perhaps we should consider adding provisions for those specific operators
(ie operator&& operator||) because that would be very useful. I can only
imagine they lose their short-circuiting properties when overloaded because
of the legacy of normal functions.
I think the interesting part is trying to do this general enough so
that it can be done for any call. Doing it for just a hardcoded set of
operators as a special case like we have now is not buying us much.
Post by Jason Rice
All of the parameters to this "using" function are expressions, but in cases
where that would be a pitfall, we are substituting it with an lvalue to the
result of the expression. This is tentative, and some have suggested it
behave more like a function and always treat the params as lvalues. For me
I see. That would kill many of the interesting use cases, sadly.
Post by Jason Rice
personally, the issue is tertiary to having something like a function that
doesn't produce a type. (constexpr params are high up there too though)
As it stands now this feature guarantees the operands are evaluated exactly
once, but I will consider adding provisional items to address short circuit
evaluation for those specific operators. (somehow)
You mean in the case you always substitute them by an lvalue?
Otherwise, if they are expressions, I would say they might not be
evaluated at all in some cases, and in other cases more than once ---
which is what is interesting about this kind of proposals and what
makes them a usable, safer replacement to macros.

Thanks for your work on this proposal!

Cheers,
Miguel
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CANiq72mT_x3NB3Y_et2waJ07fpQ%3DNp4kAegrVmH_UNVz_Ph4dQ%40mail.gmail.com.
Jason Rice
2018-09-12 20:35:21 UTC
Permalink
Post by Miguel Ojeda
I think the interesting part is trying to do this general enough so
that it can be done for any call. Doing it for just a hardcoded set of
operators as a special case like we have now is not buying us much.
You're right. The special class of parameter that is opt-in and does what
you're suggesting is probably the way to go though. I'm definitely chewing
on this.

Perhaps it could look something like this:

using foo(auto expr1, using auto expr2) {
// expr1 is evaluated and treated as an lvalue
// expr2 is pasted anywhere and not necessarily evaluated
}
Post by Miguel Ojeda
Hi Jason,
Post by Jason Rice
Perhaps we should consider adding provisions for those specific
operators
Post by Jason Rice
(ie operator&& operator||) because that would be very useful. I can only
imagine they lose their short-circuiting properties when overloaded
because
Post by Jason Rice
of the legacy of normal functions.
I think the interesting part is trying to do this general enough so
that it can be done for any call. Doing it for just a hardcoded set of
operators as a special case like we have now is not buying us much.
Post by Jason Rice
All of the parameters to this "using" function are expressions, but in
cases
Post by Jason Rice
where that would be a pitfall, we are substituting it with an lvalue to
the
Post by Jason Rice
result of the expression. This is tentative, and some have suggested it
behave more like a function and always treat the params as lvalues. For
me
I see. That would kill many of the interesting use cases, sadly.
Post by Jason Rice
personally, the issue is tertiary to having something like a function
that
Post by Jason Rice
doesn't produce a type. (constexpr params are high up there too though)
As it stands now this feature guarantees the operands are evaluated
exactly
Post by Jason Rice
once, but I will consider adding provisional items to address short
circuit
Post by Jason Rice
evaluation for those specific operators. (somehow)
You mean in the case you always substitute them by an lvalue?
Otherwise, if they are expressions, I would say they might not be
evaluated at all in some cases, and in other cases more than once ---
which is what is interesting about this kind of proposals and what
makes them a usable, safer replacement to macros.
Thanks for your work on this proposal!
Cheers,
Miguel
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ee86c093-0fc8-43c8-bcaa-011a22f745b5%40isocpp.org.
b***@gmail.com
2018-09-12 21:24:15 UTC
Permalink
Post by Miguel Ojeda
I think the interesting part is trying to do this general enough so
Post by Miguel Ojeda
that it can be done for any call. Doing it for just a hardcoded set of
operators as a special case like we have now is not buying us much.
You're right. The special class of parameter that is opt-in and does what
you're suggesting is probably the way to go though. I'm definitely chewing
on this.
using foo(auto expr1, using auto expr2) {
// expr1 is evaluated and treated as an lvalue
// expr2 is pasted anywhere and not necessarily evaluated
}
I've though about it and isn't the using idea somewhat similar to the
metaclasses proposal but applied to expressions instead of type
declarations ?
Might be a long shot but why not leveraging reflection instead yet new *RULES
*?

using foo(auto expr, auto expr2) {... } //any use of expr or expr2 is
replace with unreflexpr of the argument

foo(something, somethingelse); // foo(reflexpr(something),
reflexpr(somethingelse));

//or just the following if the above is too much
using foo(auto expr, reflexpr expr2 /*implicit conversion*/) {...}

This would allow non typed expressions to be passed to delay the resolution
of the type.
For instance, overload set => lambda:

using overloadset(reflexpr fnid)
{
return [/*?*/]<class... Args>(Args&&... args)
noexcept(noexcept(unreflexpr(fnid)(std::forward<Args>(args)...)))
-> decltype(auto) {
return unreflexpr(fnid)(std::forward<Args>(args)...);
};
}

void func();
void func(int);

aut ox = overloadset(func);
Post by Miguel Ojeda
Post by Miguel Ojeda
Hi Jason,
Post by Jason Rice
Perhaps we should consider adding provisions for those specific
operators
Post by Jason Rice
(ie operator&& operator||) because that would be very useful. I can
only
Post by Jason Rice
imagine they lose their short-circuiting properties when overloaded
because
Post by Jason Rice
of the legacy of normal functions.
I think the interesting part is trying to do this general enough so
that it can be done for any call. Doing it for just a hardcoded set of
operators as a special case like we have now is not buying us much.
Post by Jason Rice
All of the parameters to this "using" function are expressions, but in
cases
Post by Jason Rice
where that would be a pitfall, we are substituting it with an lvalue to
the
Post by Jason Rice
result of the expression. This is tentative, and some have suggested it
behave more like a function and always treat the params as lvalues. For
me
I see. That would kill many of the interesting use cases, sadly.
Post by Jason Rice
personally, the issue is tertiary to having something like a function
that
Post by Jason Rice
doesn't produce a type. (constexpr params are high up there too though)
As it stands now this feature guarantees the operands are evaluated
exactly
Post by Jason Rice
once, but I will consider adding provisional items to address short
circuit
Post by Jason Rice
evaluation for those specific operators. (somehow)
You mean in the case you always substitute them by an lvalue?
Otherwise, if they are expressions, I would say they might not be
evaluated at all in some cases, and in other cases more than once ---
which is what is interesting about this kind of proposals and what
makes them a usable, safer replacement to macros.
Thanks for your work on this proposal!
Cheers,
Miguel
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/aeb79646-ba53-49af-8777-8655a6655ede%40isocpp.org.
Jason Rice
2018-09-12 21:51:34 UTC
Permalink
My limited understanding of `reflexpr` and `unreflexpr` is that they yield
types which doesn't fit what this feature is trying to accomplish. (unless
I am misunderstanding something)
Post by b***@gmail.com
Post by Miguel Ojeda
I think the interesting part is trying to do this general enough so
Post by Miguel Ojeda
that it can be done for any call. Doing it for just a hardcoded set of
operators as a special case like we have now is not buying us much.
You're right. The special class of parameter that is opt-in and does what
you're suggesting is probably the way to go though. I'm definitely chewing
on this.
using foo(auto expr1, using auto expr2) {
// expr1 is evaluated and treated as an lvalue
// expr2 is pasted anywhere and not necessarily evaluated
}
I've though about it and isn't the using idea somewhat similar to the
metaclasses proposal but applied to expressions instead of type
declarations ?
Might be a long shot but why not leveraging reflection instead yet new *RULES
*?
using foo(auto expr, auto expr2) {... } //any use of expr or expr2 is
replace with unreflexpr of the argument
foo(something, somethingelse); // foo(reflexpr(something),
reflexpr(somethingelse));
//or just the following if the above is too much
using foo(auto expr, reflexpr expr2 /*implicit conversion*/) {...}
This would allow non typed expressions to be passed to delay the
resolution of the type.
using overloadset(reflexpr fnid)
{
return [/*?*/]<class... Args>(Args&&... args)
noexcept(noexcept(unreflexpr(fnid)(std::forward<Args>(args)...)))
-> decltype(auto) {
return unreflexpr(fnid)(std::forward<Args>(args)...);
};
}
void func();
void func(int);
aut ox = overloadset(func);
Post by Miguel Ojeda
Post by Miguel Ojeda
Hi Jason,
Post by Jason Rice
Perhaps we should consider adding provisions for those specific
operators
Post by Jason Rice
(ie operator&& operator||) because that would be very useful. I can
only
Post by Jason Rice
imagine they lose their short-circuiting properties when overloaded
because
Post by Jason Rice
of the legacy of normal functions.
I think the interesting part is trying to do this general enough so
that it can be done for any call. Doing it for just a hardcoded set of
operators as a special case like we have now is not buying us much.
Post by Jason Rice
All of the parameters to this "using" function are expressions, but in
cases
Post by Jason Rice
where that would be a pitfall, we are substituting it with an lvalue
to the
Post by Jason Rice
result of the expression. This is tentative, and some have suggested
it
Post by Jason Rice
behave more like a function and always treat the params as lvalues.
For me
I see. That would kill many of the interesting use cases, sadly.
Post by Jason Rice
personally, the issue is tertiary to having something like a function
that
Post by Jason Rice
doesn't produce a type. (constexpr params are high up there too
though)
Post by Jason Rice
As it stands now this feature guarantees the operands are evaluated
exactly
Post by Jason Rice
once, but I will consider adding provisional items to address short
circuit
Post by Jason Rice
evaluation for those specific operators. (somehow)
You mean in the case you always substitute them by an lvalue?
Otherwise, if they are expressions, I would say they might not be
evaluated at all in some cases, and in other cases more than once ---
which is what is interesting about this kind of proposals and what
makes them a usable, safer replacement to macros.
Thanks for your work on this proposal!
Cheers,
Miguel
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/b2847af1-df7d-433b-9d98-9df6706e6bc5%40isocpp.org.
Miguel Ojeda
2018-09-14 01:08:29 UTC
Permalink
Post by Jason Rice
Post by Miguel Ojeda
I think the interesting part is trying to do this general enough so
that it can be done for any call. Doing it for just a hardcoded set of
operators as a special case like we have now is not buying us much.
You're right. The special class of parameter that is opt-in and does what
you're suggesting is probably the way to go though. I'm definitely chewing
on this.
using foo(auto expr1, using auto expr2) {
// expr1 is evaluated and treated as an lvalue
// expr2 is pasted anywhere and not necessarily evaluated
}
Actually that syntax does not look bad at all! If expr1 is always
"evaluated" (like in function calls) and expr2 is always "pasted",
then possibly the second auto should be skipped (since an expression
might be of any type). It would even make the relation "using keyword"
<=> "expressions" (i.e. both introducing a parametric expression and
the expression-parameters).

By the way, this is also related to the Statements in Expressions GNU
C extension (https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs).

Another example of this syntax: the common setdefault() for Python
dicts, but we get it with laziness included:

using setdefault(auto key, using default_value) {
auto it = find(key);
if (it != end())
return *it;
return *insert(key, default_value);
}
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CANiq72%3Dzg4cXfkwh68kaATqcmcfA3wLqq_Okzqwbq_xDiDM2nQ%40mail.gmail.com.
Jason Rice
2018-09-14 18:39:10 UTC
Permalink
Post by Miguel Ojeda
By the way, this is also related to the Statements in Expressions GNU
C extension (
https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
<https://www.google.com/url?q=https%3A%2F%2Fgcc.gnu.org%2Fonlinedocs%2Fgcc%2FStatement-Exprs.html%23Statement-Exprs&sa=D&sntz=1&usg=AFQjCNFbAbvivdBhBrF8GCjuHKHsPZFazg>).
Yes, I was advised not to mention these, but I think it may be unavoidable.

I'm going to include the "macro-parameters" and just simplify the rules for
normal ones to be treated as lvalues. I'm also going to eliminate the
return-statement as it needlessly redefines what a return-statement is. (It
was also high impact in the implementation)
Post by Miguel Ojeda
Post by Jason Rice
Post by Miguel Ojeda
I think the interesting part is trying to do this general enough so
that it can be done for any call. Doing it for just a hardcoded set of
operators as a special case like we have now is not buying us much.
You're right. The special class of parameter that is opt-in and does
what
Post by Jason Rice
you're suggesting is probably the way to go though. I'm definitely
chewing
Post by Jason Rice
on this.
using foo(auto expr1, using auto expr2) {
// expr1 is evaluated and treated as an lvalue
// expr2 is pasted anywhere and not necessarily evaluated
}
Actually that syntax does not look bad at all! If expr1 is always
"evaluated" (like in function calls) and expr2 is always "pasted",
then possibly the second auto should be skipped (since an expression
might be of any type). It would even make the relation "using keyword"
<=> "expressions" (i.e. both introducing a parametric expression and
the expression-parameters).
By the way, this is also related to the Statements in Expressions GNU
C extension (
https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
<https://www.google.com/url?q=https%3A%2F%2Fgcc.gnu.org%2Fonlinedocs%2Fgcc%2FStatement-Exprs.html%23Statement-Exprs&sa=D&sntz=1&usg=AFQjCNFbAbvivdBhBrF8GCjuHKHsPZFazg>).
Another example of this syntax: the common setdefault() for Python
using setdefault(auto key, using default_value) {
auto it = find(key);
if (it != end())
return *it;
return *insert(key, default_value);
}
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c7980e9a-1d9d-4843-88dd-6908c3a445b9%40isocpp.org.
Gašper Ažman
2018-10-10 10:01:07 UTC
Permalink
Hi Jason,

Can we expect a paper at some point? The anticipation is killing me :)

G
Post by Miguel Ojeda
By the way, this is also related to the Statements in Expressions GNU
Post by Miguel Ojeda
C extension (
https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
<https://www.google.com/url?q=https%3A%2F%2Fgcc.gnu.org%2Fonlinedocs%2Fgcc%2FStatement-Exprs.html%23Statement-Exprs&sa=D&sntz=1&usg=AFQjCNFbAbvivdBhBrF8GCjuHKHsPZFazg>).
Yes, I was advised not to mention these, but I think it may be unavoidable.
I'm going to include the "macro-parameters" and just simplify the rules
for normal ones to be treated as lvalues. I'm also going to eliminate the
return-statement as it needlessly redefines what a return-statement is. (It
was also high impact in the implementation)
Post by Miguel Ojeda
Post by Jason Rice
Post by Miguel Ojeda
I think the interesting part is trying to do this general enough so
that it can be done for any call. Doing it for just a hardcoded set of
operators as a special case like we have now is not buying us much.
You're right. The special class of parameter that is opt-in and does
what
Post by Jason Rice
you're suggesting is probably the way to go though. I'm definitely
chewing
Post by Jason Rice
on this.
using foo(auto expr1, using auto expr2) {
// expr1 is evaluated and treated as an lvalue
// expr2 is pasted anywhere and not necessarily evaluated
}
Actually that syntax does not look bad at all! If expr1 is always
"evaluated" (like in function calls) and expr2 is always "pasted",
then possibly the second auto should be skipped (since an expression
might be of any type). It would even make the relation "using keyword"
<=> "expressions" (i.e. both introducing a parametric expression and
the expression-parameters).
By the way, this is also related to the Statements in Expressions GNU
C extension (
https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
<https://www.google.com/url?q=https%3A%2F%2Fgcc.gnu.org%2Fonlinedocs%2Fgcc%2FStatement-Exprs.html%23Statement-Exprs&sa=D&sntz=1&usg=AFQjCNFbAbvivdBhBrF8GCjuHKHsPZFazg>).
Another example of this syntax: the common setdefault() for Python
using setdefault(auto key, using default_value) {
auto it = find(key);
if (it != end())
return *it;
return *insert(key, default_value);
}
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c7980e9a-1d9d-4843-88dd-6908c3a445b9%40isocpp.org
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c7980e9a-1d9d-4843-88dd-6908c3a445b9%40isocpp.org?utm_medium=email&utm_source=footer>
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAANG%3DkXTS3RBP2CwN5X-r0UtFTXi9Mm0%2BXgF6v8QCASOFXxW7A%40mail.gmail.com.
Jason Rice
2018-10-10 15:32:49 UTC
Permalink
I submitted one for the San Diego mailing.

https://gist.github.com/ricejasonf/84c11ac6bb093c1ea8c380a9a466d8cb
Post by Miguel Ojeda
Hi Jason,
Can we expect a paper at some point? The anticipation is killing me :)
G
Post by Miguel Ojeda
By the way, this is also related to the Statements in Expressions GNU
Post by Miguel Ojeda
C extension (
https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
<https://www.google.com/url?q=https%3A%2F%2Fgcc.gnu.org%2Fonlinedocs%2Fgcc%2FStatement-Exprs.html%23Statement-Exprs&sa=D&sntz=1&usg=AFQjCNFbAbvivdBhBrF8GCjuHKHsPZFazg>).
Yes, I was advised not to mention these, but I think it may be unavoidable.
I'm going to include the "macro-parameters" and just simplify the rules
for normal ones to be treated as lvalues. I'm also going to eliminate the
return-statement as it needlessly redefines what a return-statement is. (It
was also high impact in the implementation)
Post by Miguel Ojeda
Post by Jason Rice
Post by Miguel Ojeda
I think the interesting part is trying to do this general enough so
that it can be done for any call. Doing it for just a hardcoded set
of
Post by Jason Rice
Post by Miguel Ojeda
operators as a special case like we have now is not buying us much.
You're right. The special class of parameter that is opt-in and does
what
Post by Jason Rice
you're suggesting is probably the way to go though. I'm definitely
chewing
Post by Jason Rice
on this.
using foo(auto expr1, using auto expr2) {
// expr1 is evaluated and treated as an lvalue
// expr2 is pasted anywhere and not necessarily evaluated
}
Actually that syntax does not look bad at all! If expr1 is always
"evaluated" (like in function calls) and expr2 is always "pasted",
then possibly the second auto should be skipped (since an expression
might be of any type). It would even make the relation "using keyword"
<=> "expressions" (i.e. both introducing a parametric expression and
the expression-parameters).
By the way, this is also related to the Statements in Expressions GNU
C extension (
https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
<https://www.google.com/url?q=https%3A%2F%2Fgcc.gnu.org%2Fonlinedocs%2Fgcc%2FStatement-Exprs.html%23Statement-Exprs&sa=D&sntz=1&usg=AFQjCNFbAbvivdBhBrF8GCjuHKHsPZFazg>).
Another example of this syntax: the common setdefault() for Python
using setdefault(auto key, using default_value) {
auto it = find(key);
if (it != end())
return *it;
return *insert(key, default_value);
}
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c7980e9a-1d9d-4843-88dd-6908c3a445b9%40isocpp.org
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c7980e9a-1d9d-4843-88dd-6908c3a445b9%40isocpp.org?utm_medium=email&utm_source=footer>
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ee221a61-2afe-4d88-8b39-6c44614f2846%40isocpp.org.
Barry Revzin
2018-08-31 00:34:16 UTC
Permalink
Can I pass one of these things into a function template? For instance:

std::vector v{1, 2 3};
auto sum = std::accumulate(v.begin(), v.end(), 0, add);

Does that work? How?
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f6398037-049e-427e-8351-abf12acb60d4%40isocpp.org.
Jason Rice
2018-08-31 00:47:58 UTC
Permalink
Post by Barry Revzin
Can I pass one of these things into a function template?
No, not directly, but you could make it the member of a class to make an
invokable object.

Something like:

```
struct add {
using operator()(auto x, auto y) { return x + y; }
};
```

I should probably add a note about an implicit `this` and possibly an
optional const qualifier for when it is a member. (or mutable?)
Post by Barry Revzin
std::vector v{1, 2 3};
auto sum = std::accumulate(v.begin(), v.end(), 0, add);
Does that work? How?
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f6398037-049e-427e-8351-abf12acb60d4%40isocpp.org
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CANfsYuz1aMwdk-PCSyqFq6aNMGbQLSvV6w1pd2KzKWJqEaDhDA%40mail.gmail.com.
Bengt Gustafsson
2018-08-31 04:54:49 UTC
Permalink
I faail to understand how this differs from doing the same but replacing the using with auto. If you worry about compile times there is nothing that hinders current clmpikers from taking a shortcut if all parameter types are plain auto...

Please provide an example of code that can be written using this feature but not with auto return type. Preferably understandable without requiring too much knowledge of higher math.

To me it would be more interesting if we could replace a larger subset of macros, maybe 'using' as a parameter type which substitutes in the body at an early parsing phase or something like that...
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/53248610-d4ed-4a28-b5f8-bf7c61247eb9%40isocpp.org.
Jason Rice
2018-08-31 08:00:23 UTC
Permalink
Admittedly, compile time performance is the main motivation here. Think of
this as having the same utility that a type alias template has over using a
class template.

However, there are a couple of things that this can do that normal
functions cannot because we are just generating AST in the same
context/scope as where it is invoked.

Here is an example of constexpr parameters:

```
#include <type_traits>

template <bool>
struct unpack_string_t;

template <>
struct unpack_string_t<false> {
using operator()(auto str, auto ...chars, auto fn) {
if constexpr(str[sizeof...(chars)] == 0) {
return fn(chars...);
}
else {
return unpack_string<sizeof...(chars) > 9000>{}(str, chars...,

str[sizeof...(chars)], fn);
}
}
};

inline constexpr unpack_string_t unpack_string;

template <char...>
struct ct_string { };

struct make_ct_string_t {
using operator()(auto ...chars) {
return ct_string<chars...>{};
}
};

inline constexpr make_ct_string_t make_ct_string;


int main() {
ct_string<'f', 'o', 'o'> x = unpack_string("foo", make_ct_string);
}
```

To me it would be more interesting if we could replace a larger subset of
Post by Bengt Gustafsson
macros, maybe 'using' as a parameter type which substitutes in the body at
an early parsing phase or something like that...
I'm not sure what you mean by "replace a larger subset of macros".

Having any parameter in a normal function have the ability to be a "using"
parameter sounds interesting, but function scope is isolated so arbitrary
expressions would be out. If "using" parameters were just constexpr values
then that function would have a different type for every value it was
invoked with.

On Thu, Aug 30, 2018 at 9:54 PM Bengt Gustafsson <
Post by Bengt Gustafsson
I faail to understand how this differs from doing the same but replacing
the using with auto. If you worry about compile times there is nothing that
hinders current clmpikers from taking a shortcut if all parameter types are
plain auto...
Please provide an example of code that can be written using this feature
but not with auto return type. Preferably understandable without requiring
too much knowledge of higher math.
To me it would be more interesting if we could replace a larger subset of
macros, maybe 'using' as a parameter type which substitutes in the body at
an early parsing phase or something like that...
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/53248610-d4ed-4a28-b5f8-bf7c61247eb9%40isocpp.org
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CANfsYuwwU0MHV%2BSaDZQZetwTzJpvjJ%2BptFzK4A4CQHWLaHecYg%40mail.gmail.com.
s***@gmail.com
2018-08-31 14:22:34 UTC
Permalink
would the following work:

using forward(auto x) { return std::forward<decltype(x)&&>(x); }

using lazy(auto x) { return[]{return x;}; }
auto x = lazy(func());
x(); //calls func()

if so maybe allowing those to be used as custom type conversion could be interesting :

lazy x = func();
void f(lazy{} x);
f(func());
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/1cc9f0c3-058a-4063-91c5-1b19107cae79%40isocpp.org.
Richard Hodges
2018-08-31 14:31:39 UTC
Permalink
Post by s***@gmail.com
using forward(auto x) { return std::forward<decltype(x)&&>(x); }
I think this is brilliant. It's essentially namespace-scoped macros, but
better. It solves the problem of the unfriendly std::forward without
changing the language or polluting the global namespace.
Post by s***@gmail.com
using lazy(auto x) { return[]{return x;}; }
auto x = lazy(func());
x(); //calls func()
lazy x = func();
void f(lazy{} x);
f(func());
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/1cc9f0c3-058a-4063-91c5-1b19107cae79%40isocpp.org
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALvx3hbFrw9vC-q0K8A1qJDpFTSczOMoPVFTOWJ8Fb134t7bpQ%40mail.gmail.com.
Jason Rice
2018-08-31 15:43:27 UTC
Permalink
Post by s***@gmail.com
auto x = lazy(func());
So here is the problem with pasting the expression when it can contain side
effects. Intuitively, the user expects `func()` to be evaluated immediately.
This is the reason the rules as they are written now only allow pasting the
expression if it evaluates to a prvalue contstant-expression.

So, unless we are willing to throw inhibition to the wind, I don't know
that is a good idea to paste expressions that could contain side effects
(contradictory to what I said earlier).

That does seem very powerful though.
Post by s***@gmail.com
using forward(auto x) { return std::forward<decltype(x)&&>(x); }
using lazy(auto x) { return[]{return x;}; }
auto x = lazy(func());
x(); //calls func()
lazy x = func();
void f(lazy{} x);
f(func());
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/a186bc7f-81ea-4430-8e63-56ae706dee3f%40isocpp.org.
Loading...