C++ Logo

std-proposals

Advanced search

Re: [std-proposals] declfunc - parameters deduced from arguments

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Wed, 5 Jun 2024 23:37:30 +0100
On Wed, Jun 5, 2024 at 4:46 PM Giuseppe D'Angelo wrote:
>
> How is this different from
>
> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2825r2.html


At the beginning of the paper is:

    template <typename R, typename Args...>
    struct my_erased_wrapper {
      using fptr = R(*)(Args_...);
      fptr erased = +[](my_erased_wrapper* self, auto&&... args_) -> R {
        return self->fptr(std::forward<decltype>(args_)...);
      };
    };

Observation 1: typename Args... is a typo for typename... Args
Observation 2: It says "self->ptr" but 'ptr' isn't a member (it's a type)

declcall fails for constructors and destructors, and maybe this is
fine, but an alternative could be for it to return a member function
pointer. So for example if you had:

    struct S {
        int n;
        S(int const arg) : n(arg) {}
        S(double const arg) : n( static_cast<int>(arg + 0.5) ) {}
    };

and then if you were to do:

    declcall( S(7. 6) )

then it could return the address of the double-accepting-constructor
inside a "void (S::*)(double)". Then we could do the following:

    int main(void)
    {
        S var(5);
        var.~S();
        constexpr auto mfp = declcall( S(6.2) );
        (var.*mfp)(6.3);
    }

Similarly, if you were to write:

    declcall( std::declval<S&>().~S() )

then it could return the address of the destructor inside a "void
(S::*)(void)", and then we could do:

    int main(void)
    {
        S var(5);
        constexpr auto mfp = declcall( std::declval<S&>().~S() )
        (var.*mfp)();
        ::new(&var) S(6);
    }

C++ has never allowed us to take the address of a constructor or
destructor, but this has always been a needless restriction. Getting
the address of a destructor isn't so much of a big deal since we can
alternatively take the address of the following function:

    template<typename T>
    constexpr void call_destructor(T *const p) noexcept(noexcept(p->~T()))
    {
        p->~T();
    }

However, being able to take the address of a constructor with declcall
would be helpful since we can't take the address of the following
function without knowing what conversions of arguments will take
place:

    template<typename T, typename... Params>
    constexpr void call_constructor(T *const p, Params&&... args)
    {
        std::construct_at<T>( p, std::forward<Params>(args)... );
    }

So I'm in favour of being able to use declcall to get the addresses of
constructors and destructors.

And just one last thing . . . and it's not particularly relevant to
declcall . . . but it always bugged me that constructors and
destructors were the same name as the class . . . I don't know why
Bjarne did that . . . it would have made so much more sense for them
to be normal member functions which return 'void' and are named
"_Constructor" or "_Destructor". I'd like if C++26 allowed us to
write:

    struct S {
        void _Constructor(void) {}
    };

instead of:

    struct S {
        S(void) {}
    };

meaning we could simply do:

    void (S::*)(void) = &S::_Constructor;

Received on 2024-06-05 22:37:43