c++volatilemember-functionsexplicit-object-parameter

How to keep from duplicating methods in volatile classes


Suppose I have the following very simple class:

class A
{
public:
    static constexpr A make() { return A{}; }

    constexpr A() : _v(0) {}

    constexpr A& setV(int v) { _v = v; return *this; }

private:
    int _v;
};

If I try to use it as follows:

int main()
{
    volatile A a1;
    a1.setV(10);

    //OR

    //The optimizer will optimize this chain of constexpr calls into a single "store" instruction
    a1 = A::make().setV(10); //More chaining here

    return 0;
}

The code will not compile.

I understand why this is true based upon: Defining volatile class object

I know that the solution would be to add an additional method like so:

class A
{
public:
    constexpr A() : _v(0) {}

    volatile A& setV(int v) volatile { _v = v; return *this; }
    constepxr A& setV(int v) { _v = v; return *this; }

private:
    int _v;
};

As an aside, I am aware that returning the volatile reference will issue a warning if it is not used.

My question is, is there any way I can avoid code duplication in this case? Both implementations of setV will always be the same. Thus, if I add/change more methods, I have to maintain them both which could get messy if they aren't so trivial. The only difference is one of type qualifiers...

Since there have been some mentions of this in the comments, I thought I would note that I need volatile here because I am attempting to eventually implement "class overlay" for hardware peripheral register access on an embedded system.


Solution

  • In C++23, you can use an explicit object parameter (also known as deducing this) for this purpose:

    class A
    {
    public:
        A() : _v(0) {}
        template <class Self>
        constexpr auto&& setV(this Self&& self, int v) {
            self._v = v; return self;
        }
    private:
        int _v;
    };
    

    Unfortunately, as of this writing the only compiler that supports this is the latest version of Microsoft Visual C++.