Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #67207
| From | "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> |
|---|---|
| Newsgroups | comp.lang.c++ |
| Subject | Re: Tricky! |
| Date | 2019-07-30 18:00 +0200 |
| Organization | A noiseless patient Spider |
| Message-ID | <qhppjb$ojs$1@dont-email.me> (permalink) |
| References | <qhmmgr$dih$1@news.albasani.net> <7995a414-14ec-47ae-8afc-9ebcc520e30d@googlegroups.com> <qhn54k$dk6$1@dont-email.me> <86imrj8szn.fsf@mailhub.linuxsc.com> |
On 30.07.2019 17:03, Tim Rentsch wrote:
> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
>
>> On 29.07.2019 15:30, <<D6 F6 [05b6]>> Tiib wrote:
>>
>>> On Monday, 29 July 2019 14:49:58 UTC+3, Bonita Montero wrote:
>>>
>>>> I need a class-function / method that returns a function-pointer
>>>> to the same type of class-function. How do I implement this? I
>>>> need this to have a kind of state-machine where each state-func-
>>>> tion returns a pointer to the next state function. I.e I would
>>>> write: "while( (fn = state->*fn()) != nullptr );". I see no way
>>>> to define the type of fn since it is recursive.
>>>
>>> Perhaps there are no way to make a function that return function
>>> pointer of its own type. However I do not understand the need
>>> of it.
>>
>> I think she is inspired by (possibly someone else who is inspired
>> by) an article by the Go language creator.
>>
>> As I recall his examples work nicely in Go, or assembly language, or
>> a more dynamic language like Python, but have to be rewritten with
>> some indirection for a language with strong static type checking
>> like C++.
>
> The problem here is not strong static type checking but the lack
> of recursive types in C++. A language can have recursive types
> and also have strong static type checking.
>
>> The reason for doing it that way, in languages where it's simple, is
>> the textual simplicity of the source code. Since it doesn't give
>> that textual simplicity in C++, it's not a good way in C++. It's
>> doable, just not in any practical way.
>
> That depends on what is meant by "practical".
Short and clear source code and reasonably good efficiency.
> It can be done like this:
>
> #include <iostream>
>
> class State {
> using Nexter = ...;
>
> public:
> State(){}
> Nexter r0(){ return &State::r1; }
> Nexter r1(){ return &State::r2; }
> Nexter r2(){ return &State::rn; }
> Nexter rn(){ return 0; }
> };
>
> void
> run_state_machine(){
> State *s = new State;
>
> for( auto f = &State::r0; f; f = (s->*f)() ){
> ::std::cout << "Got one\n";
> }
> }
Yes, that's mainly the basic technique I had in mind: an extra level of
indirection, the solution to every computer science problem.
Nit-picks: (1) a State instance doesn't actually hold state, yet the
member functions are not `static`, and (2) there's a needless dynamic
allocation and memory leak.
Fixing those issue, it can go like this (in practice one would have some
input argument to each function, so it can decide which state to go to):
class State
{
struct Nexter
{
using Func = auto() -> Nexter;
Func* m_p_func;
operator Func* () const { return m_p_func; }
Nexter( Func* const f ): m_p_func( f ) {}
};
State() = delete;
public:
static auto r0() -> Nexter { return &State::r1; }
static auto r1() -> Nexter { return &State::r2; }
static auto r2() -> Nexter { return &State::rn; }
static auto rn() -> Nexter { return nullptr; }
};
#include <iostream>
using namespace std;
auto main() -> int
{
for( auto f = &State::r0; f; f = f() ) {
cout << "State " << reinterpret_cast<void const*>( f ) <<
"." << endl;
}
}
Here the reinterpret_cast is only conditionally supported by the
standard (since C++11, in order to support Posix), so it's not 100%
portable. I guess that on a Harvard architecture it won't compile. But
then one would have more labor-intensive problems to deal with...
> with a fairly short (five-ish lines) elaboration for the "...".
Not sure what you're thinking of there?
> Personally I think this approach offers a fairly nice textual
> simplicity, and is eminently practical.
>
> If someone thinks five lines of overhead is too much, the "..."
> can be made into a template, giving
>
> using Nexter = WrapMemberFunctionPointer< State >;
>
> which provides an even nicer source text.
Well, to my mind the indirection adds complexity so that even though the
code is short it's not IMO /clear/, and for debugging it's not so clear
which state one is in, just by looking at a function address.
But, subjective opinion. ;-)
Cheers!,
- Alf
Back to comp.lang.c++ | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
Tricky! Bonita Montero <Bonita.Montero@gmail.com> - 2019-07-29 13:49 +0200
Re: Tricky! Öö Tiib <ootiib@hot.ee> - 2019-07-29 06:30 -0700
Re: Tricky! "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-07-29 17:59 +0200
Re: Tricky! Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-07-30 08:03 -0700
Re: Tricky! "Rick C. Hodgin" <rick.c.hodgin@gmail.com> - 2019-07-30 11:20 -0400
Re: Tricky! "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-07-30 18:00 +0200
Re: Tricky! Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-08-10 14:19 -0700
Re: Tricky! Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-07-30 07:31 -0700
Re: Tricky! Öö Tiib <ootiib@hot.ee> - 2019-07-30 09:22 -0700
Re: Tricky! Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-08-10 14:45 -0700
Re: Tricky! Öö Tiib <ootiib@hot.ee> - 2019-08-11 03:23 -0700
Re: Tricky! Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-08-17 22:02 -0700
Re: Tricky! Öö Tiib <ootiib@hot.ee> - 2019-08-17 23:53 -0700
Re: Tricky! Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-08-18 05:22 -0700
Re: Tricky! Sam <sam@email-scan.com> - 2019-07-29 20:51 -0400
Re: Tricky! Sam <sam@email-scan.com> - 2019-07-29 20:52 -0400
Re: Tricky! Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-07-30 13:58 +0100
Re: Tricky! Bonita Montero <Bonita.Montero@gmail.com> - 2019-08-11 09:06 +0200
csiph-web