C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Let constructor know if object is const or volatile

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Fri, 29 Sep 2023 09:07:59 +0100
On Thu, Sep 28, 2023 at 12:05 PM Sebastian Wittmeier wrote:
>
> So you are asking for a way to know at runtime inside a constructor, whether the constructed object is const or non-const?
> Like an implicit parameter? Not ABI compatible, performance cost.
> Or at compile-time? Then the constructor would have to be a template to generate two functions.
> It is not supported by the current standard.
> As alternative you could use two different factory functions instead.


There are a few possibilities for implementing this (and for the time
being I'll ignore the problem of breaking ABI). I'm gonna use x86_64
Linux SystemV as a sample platform.

Possibility 1) Pass a hidden parameter to the constructor (e.g. put it
in the RDI register and move everything else down one place). The
hidden argument could be 0 for non-const non-volatile, 1 for const
non-volatile, 2 for non-const volatile, and 3 for non-const
non-volatile, and then inside the constructor, we could have:

    Monkey::Monkey(void)
    {
        if ( std::this_is_const() ) DoSomething();
    }

This would work fine but it would mean a change to the ABI for calling
the constructor.

Possibility 2) Instead of passing a hidden parameter to the function,
have a global thread-local variable to denote the constness and
volatileness of the current object being constructed. The syntax for
this would be the same:

    Monkey::Monkey(void)
    {
        if ( std::this_is_const() ) DoSomething();
    }

This however would not alter the calling convention for invoking the
constructor. The compiler would just have to make sure to set the
global thread-local variable properly before invoking the constructor.

Possibility 3) Have an implicit type '_This_t' defined within the body
of the constructor. Of course, types cannot change at runtime, and so
the distinction would have to be made at compile-time, meaning that
each constructor would have four copies. So when we write the
following:

    Monkey::Monkey(void)
    {
        if ( std::is_const_v(std::remove_pointer_t<_This_t>) ) DoSomething();
    }

It gets compiled to four separate funtions:

    Monkey::Monkey(void)
    {
        typedef Monkey *_This_t;
        if ( std::is_const_v(std::remove_pointer_t<_This_t>) ) DoSomething();
    }

    Monkey::Monkey(void)
    {
        typedef Monkey const *_This_t;
        if ( std::is_const_v(std::remove_pointer_t<_This_t>) ) DoSomething();
    }

    Monkey::Monkey(void)
    {
        typedef Monkey volatile *_This_t;
        if ( std::is_const_v(std::remove_pointer_t<_This_t>) ) DoSomething();
    }

    Monkey::Monkey(void)
    {
        typedef Monkey const volatile *_This_t;
        if ( std::is_const_v(std::remove_pointer_t<_This_t>) ) DoSomething();
    }

This would then beg the question: If the constructor contains a static
variable, is there just one copy of that variable shared between the
four implementations, or is there four separate variables? If the
answer to this question were 1, then we would have to consider what
happens if you write the following:

    Monkey::Monkey(void)
    {
        static std::vector<_This_t> myvec;

        if ( std::is_const_v(std::remove_pointer_t<_This_t>) ) DoSomething();
    }

In the above snippet, the variable 'myvec' cannot be shared between
the four implementations of the constructor. Perhaps in this instance
we could stipulate:
    'Inside a constructor, the type of any static variable cannot be
dependant upon _This_t'.

When it comes to the initialisation of a static-duration variable
which is shared between the four implementations of the constructor,
well the four implementations will share a common 'once_flag' for this
purpose to ensure the variable only gets initialised once.

Received on 2023-09-29 08:08:11