On Tue, Oct 1, 2024 at 6:19 AM Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> wrote:

    class Monkey {
    public:
        virtual double Do(int const arg) { return arg * 3.0; }
        virtual int Do(char, char, char) { return 6;         }
    };

    class BlueMonkey : public Monkey {
    public:
        virtual int Act(auto&&... args)
        {
            return this->Do( static_cast<decltype(args)>(args)... );
        }
    };
[...]
      error: implicit templates may not be 'virtual'
           |         virtual int Act(auto&&... args)

[...]
Of course this 'Act' method _looks_ _like_ a template function because
it has 'auto' in its parameter list, but really since 'args' is passed
directly to the 'Do' method, we know that 'Do' really has only two
possible signatures:

        double Do(int);
        int Do(char, char, char);

which means that 'Act' can really only have two possible signatures:

        double Act(int);
        int Act(char, char, char);

Since 'Act' is virtual, we cannot tell what it does with its `args`.
For example, it might only care about the arity of the pack:
    class LightBlueMonkey : public BlueMonkey {
      int Act(auto&&... args) override { return sizeof...(args); } 
    };
or it might care about everything:
    class DarkBlueMonkey : public BlueMonkey {
      int Act(auto&&... args) override { (std::cout << ... << args); return 0; } 
    };

So your idea isn't implementable.

"But I, the human programmer, know what 'Act' will do! I don't intend to override it in any child class!" — Then you should not mark it `virtual`. Problem solved.
This is known as the "Non-Virtual Interface Idiom" and/or the "Template Method Pattern," and it's a very good idea. I use it myself.
The idea is to permit overriding of the little pieces of work encased in 'Do' methods, but not permit overriding of the overall "pattern" of how those pieces are put together in the 'Act' method.

    class Monkey {
    private:
        virtual double Do(int const arg) = 0;
        virtual int Do(char, char, char) = 0;
    public:
        int Act(auto&&... args) {
            return this->Do( static_cast<decltype(args)>(args)... );
        }
    };

 
I came up with this idea yesterday [...]
        virtual bool SetGrade(unsigned const arg) override {
            // Do logging
            return this->pPM->SetGrade(arg);
        }
        virtual bool SetLevel(unsigned const arg) override {
            // Do logging
            return this->pPM->SetLevel(arg);
        }
[...]
Look at how I had to write out each individual method, SetGrade and
SetLevel (there was more like a dozen of them to write out). It would
have been handy, if [...] I had been able to write:

        virtual decltype(auto) SetLevel(auto &&args) override
        {
            // Do logging
            return this->pPM->SetLevel( static_cast<decltype(args)>(args)... );
        }

That wouldn't help you; you need to also change the name of the function (and the name of the function it calls) from SetLevel to SetGrade.
This is the sort of thing where people say "Reflection and code generation will solve that!"

HTH,
Arthur