What if we specialized a function template templated on bool, to have one version that's a coroutine, and one version that's a normal function?

Maybe something like: https://godbolt.org/z/7TEnb6
(Code adapted from cppreference as an example)

On Wed, Jan 20, 2021 at 4:04 PM Arthur O'Dwyer via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hi Chuanqi,

I brought this up on the cpplang Slack (in the #coroutines channel). Personally I tend to agree with your take, but the consensus in Slack seemed to be "You shouldn't want that."

I'm interested to see your Clang patch. (How short is it?)  It might be interesting to see if you could rework it into a conforming extension (by adding a diagnostic "ISO C++ forbids coroutines to contain `return` statements, even in discarded statements") and post it for review.

To solve your actual problem, in C++20, consider using plain old macros, e.g.

namespace MaybeCoroStuff {
std::conditional_t<USE_CORO, CoroType, ValueType>
func(ValueType v) {
#if USE_CORO
    co_return v;
#else
    return v;
#endif
}
} // namespace MaybeCoroStuff

This still lets you choose between USE_CORO=0 and USE_CORO=1 at compile time. The downside is that (at least with this naive approach) it lets you choose only one of these per compilation. If you want to have both the coro and non-coro versions living side by side in the same program, you'd have to put this in a header file and do, like,

#define USE_CORO 1
#define MaybeCoroStuff CoroStuff
#include "maybe-coro-stuff.h"
#undef MaybeCoroStuff
#undef USE_CORO

#define USE_CORO 0
#define MaybeCoroStuff NonCoroStuff
#include "maybe-coro-stuff.h"
#undef MaybeCoroStuff
#undef USE_CORO

–Arthur


On Wed, Jan 20, 2021 at 1:48 AM chuanqi.xcq via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hi! I am Chuanqi Xu, a new compiler engineer, who is new to this community too. Remind me if I do anything wrong.

The following example shows my motivation. 

```
template<bool UseCoro>
std::conditional_t<UseCoro, CoroType, ValueType>
func(ValueType v) {
    if constexpr (UseCoro)
        co_return v;
    else
        return v;
}
```

I want to use constexpr-if grammer to make it possible that programmer could choose to use a normal function or a coroutine at compile time. However, both gcc and clang emit error for above example because we can't use `return` in a coroutine.

Then I find this behavior is desired by the standard.

8.5.2.2 from N4878 says:
```

If the if statement is of the form if constexpr, the value of the condition shall be a contextually converted

constant expression of type bool (7.7); this form is called a constexpr if statement. If the value of the converted

condition is false, the first substatement is a discarded statement, otherwise the second substatement, if 

present, is a discarded statement. During the instantiation of an enclosing templated entity (13.1), if the

condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.

```

and 8.7.5.1 from N4878 says:
```

A coroutine returns to its caller or resumer (9.5.4) by the co_return statement or when suspended (7.6.2.4).

A coroutine shall not enclose a return statement (8.7.4).

[Note 1 : For this determination, it is irrelevant whether the return statement is enclosed by a discarded statement

(8.5.2). —end note]

```

I think the Note in 8.7.5.1 is a little bit odd. From my point of view, the logic is:
1. a function who contains one of `co_*` keywords is a coroutine.
2. a template function stands for a family of functions. Only a instantiated template function stands for a function.
3. From 1 and 2, we should judge whether a template function is a coroutine after it is instantiated.

So I am a little bit confusing why there is a note in 8.7.5.1. And I think we should remove this constraint if there is no other special reasons.

I did a simple patch in clang which could make the example above to compile. So I think the implementation would not be very hard.

The reason why we want this feature is that my collegues find that: coroutine get great improvement in some situations while getting big regression in other situations.
As a compiler programmer, I think it is hard to optimize coroutine fast as normal function in all cases.
So I think it would be a solution that programmer could choose to use a coroutine function or a normal function at compile time.
 
Thanks,
Chuanqi
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals