0

I am working on a project started back to 1980s, my mission is to substitute the primitive double with the Dummy class I create. The following is the simplified problematic code:

class Dummy{
private:
    double d;
public:
    Dummy(){};
    Dummy(double d1): d{d1}{}; 
    Dummy& operator = ( const Dummy& dm ) {
        d = dm.d;
        return *this;
    }
    Dummy& operator = ( const volatile Dummy& dm ) {
        d = dm.d;
        return *this;
    }
};

struct A{
    bool isDummy;
    union{
        Dummy dm ;
        int i; 
    }B;
};

int main(){
    struct A a1;
    a1.B= 1.1;
    struct A a2;
    a2.B = a1.B;
    return 0;
}

And the following is the error message I got, when I compiled it with x86-64 gcc 11.2:

<source>: In function 'int main()':
<source>:38:14: error: use of deleted function 'A::A()'
   38 |     struct A a1;
      |              ^~
<source>:17:8: note: 'A::A()' is implicitly deleted because the default definition would be ill-formed:
   17 | struct A{
      |        ^
<source>:17:8: error: use of deleted function 'A::<unnamed union>::<constructor>()'
<source>:19:10: note: 'A::<unnamed union>::<constructor>()' is implicitly deleted because the default definition would be ill-formed:
   19 |     union{
      |          ^
<source>:20:15: error: union member 'A::<unnamed union>::dm' with non-trivial 'Dummy::Dummy()'
   20 |         Dummy dm ;
      |               ^~
<source>:40:14: error: use of deleted function 'A::A()'
   40 |     struct A a2;
      |              ^~
<source>:41:15: error: use of deleted function 'A::<unnamed union>& A::<unnamed union>::operator=(const A::<unnamed union>&)'
   41 |     a2.B = a1.B;
      |               ^
<source>:19:10: note: 'A::<unnamed union>& A::<unnamed union>::operator=(const A::<unnamed union>&)' is implicitly deleted because the default definition would be ill-formed:
   19 |     union{
      |          ^
<source>:20:15: error: union member 'A::<unnamed union>::dm' with non-trivial 'Dummy& Dummy::operator=(const Dummy&)'
   20 |         Dummy dm ;
      |               ^~

However when I compiled the original project with g++ 9.3.0, only the problem on the line 41 is reported, which is the problem I want to solve.

I need the overloaded operator to enable copying fromm volatile instances to non-volatile ones for the project.

I have seen the solution here, which is to name the unnamed union and make it a tagged union, but the problem of this solution is that this struct is widely used, if I do it in this way, it will involve too many manual modifications.

I tried to overload operator "=" for the unnamed union with the following code, which doesn't work:

union {
    Dummy dm ;
    int i; 
    void* operator=(const Dummy& d){
        this->dm = d;
        return this;
    };
}B;

How can I solve this problem? Thank you.

timrau
  • 22,578
  • 4
  • 51
  • 64
Ciriously
  • 47
  • 1
  • 7
  • 2
    What's the purpose of `volatile` in `Dummy& operator=( const volatile Dummy& dm )`? – Ted Lyngmo Feb 23 '22 at 11:20
  • @Ted Lyngmo Since in other files it involves copying files between volatile and non-volatile instances of the Dummy class, I added the overloaded operator "=" to enable aforementioned copying using the reference here: https://stackoverflow.com/questions/60660058/c-assign-operator-to-copy-between-volatile-and-non-volatile-instances-of-a-cla – Ciriously Feb 23 '22 at 11:29
  • 2
    Why do you have `volatile` instances of the class? Are they connected to hardware that can change the state of the instances so that the compiler don't have any knowledge about when the state may change? – Ted Lyngmo Feb 23 '22 at 11:34
  • @Ted Lyngmo It's an open-source project called ngspice on sourceforge to simulate eletronic circuitries, I am asking the maintainance team the same question. – Ciriously Feb 23 '22 at 11:46
  • 1
    Ideally, you should probably replace `A` with `std::variant`. – eerorika Feb 23 '22 at 11:47
  • 1
    @Ragnarsdottir I found this interesting comment in `src/main.c`: _"`volatile` added to resolve GCC `-Wclobbered`"_. About `-Wclobbered`: _"Warn for variables that might be changed by `longjmp` or `vfork`."_ The `volatile` variables are two `bool`s and one `FILE*`. Some of the device files has a few `volatile` variables two, but they are all of fundamental types. – Ted Lyngmo Feb 23 '22 at 12:03
  • @TedLyngmo Yes, I stated it "my mission is to substitute the primitive double with the Dummy class I create." What is your suggestion,sir? – Ciriously Feb 23 '22 at 12:16
  • 1
    @Ragnarsdottir Unless you have hardware connected to instances of `Dummy`, skip `volatile`. I'd try to remove the uses of `longjmp`s too. They are a pain. – Ted Lyngmo Feb 23 '22 at 12:19
  • @TedLyngmo By `longjmp` do you mean `goto`? – Ciriously Feb 23 '22 at 13:29
  • @eerorika I can't do that, it involves too many changes and corresponding tests in this circumstance, but thank you for your idea anyway. – Ciriously Feb 23 '22 at 13:31
  • No, I mean `setjmp`/`longjmp`. If the code contains that, try to redesign it instead of making things `volatile`. – Ted Lyngmo Feb 23 '22 at 14:06
  • @TedLyngmo That certainly is outside the scope of my tasks – Ciriously Feb 23 '22 at 15:21

1 Answers1

2

Not sure if those modifications are possible for you, but following compiles

class Dummy
{
private:
    double d;
public:
    Dummy() = default;
    Dummy(double d1): d{d1}{}
    Dummy& operator = ( const Dummy& dm ) = default;
};

struct A{
    bool isDummy = true;
    union{
        Dummy dm;
        int i;

        decltype(auto) operator=(double d) { dm = d; return *this; }
    }B;

};

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302