1

I would like to copy, in both directions, between volatile and non-volatile instances of a class. The following uses the assignment operator for the copy. If the macro "ordinary_cpp" is defined everything compiles as expected. If the macro is not defined, which enables "volatile", it copies a non-volatile to a volatile, but errors on the opposite, and always errors on the return of *this.

I hope someone can tell me the correct syntax to return *this, and how I can assign a volatile to a non-volatile. Thanks.

#define ordinary_cpp
#ifdef ordinary_cpp
  #define cv_qual
  #define thiserrormacro(arg) arg
  #define hopefulmacro(arg) arg
#else
  #define cv_qual volatile
  #define thiserrormacro(arg)
  #define hopefulmacro(arg)
#endif

struct Class {
  int data;
  Class operator = ( Class lhs ) cv_qual {
    data = lhs.data;
    thiserrormacro(return *this;)
  }
};

void test(){
  Class         nonvol;
  Class cv_qual vol;

  vol = nonvol;

  hopefulmacro(nonvol = vol;)
}
Pete D.
  • 165
  • 1
  • 12
  • I don't see how you get that through the compilation with or without the macro defined. You need to turn a lot more warnings on. If you're using `g++` or `clang++` start with these: `-Wall -Wextra -pedantic -pedantic-errors` – Ted Lyngmo Mar 12 '20 at 18:42
  • May I ask if you know what `volatile` does? – Tanveer Badar Mar 12 '20 at 19:07

1 Answers1

4

You need 4 overloads, for

nonvol = nonvol;
nonvol = vol;
vol = nonvol;
vol = vol;

It would be something like

struct Class {
  int data;
  Class& operator = ( const Class& lhs ) {
    data = lhs.data;
    return *this;
  }
  volatile Class& operator = ( const Class& lhs ) volatile {
    data = lhs.data;
    return *this;
  }
  Class& operator = ( const volatile Class& lhs ) {
    data = lhs.data;
    return *this;
  }
  volatile Class& operator = ( const volatile Class& lhs ) volatile  {
    data = lhs.data;
    return *this;
  }
};

But don't bother. volatile is pretty vestigial at this point, and it definitely doesn't mean "safe to use with threads".

Tanveer Badar
  • 5,438
  • 2
  • 27
  • 32
Caleth
  • 52,200
  • 2
  • 44
  • 75
  • gcc will complain if you use the `volatile` ones with a [warning](https://stackoverflow.com/questions/13869318/gcc-warning-about-implicit-dereference) and Visual Studio will complain with a different warning (*"multiple assignment operators specified"*). It's very unusual to do this, but this answer should work. You can silence the gcc warning by making the `volatile` overloads return `void`. It's hard to think about what chaining assignments on a volatile object means anyway. – François Andrieux Mar 12 '20 at 18:47
  • Thanks Caleth. Unfortunately those nice people at Nvidia don't agree with you - https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#memory-fence-functions - void __threadfence - " this is ensured by using the volatile keyword as detailed in Volatile Qualifier. " + thanks Francois - gcc does warn. – Pete D. Mar 13 '20 at 09:58
  • That's not what they are saying. volatile is not sufficient for avoiding data races. If you use the synchronisation provided by the language, it is also not necessary. – Caleth Mar 13 '20 at 10:21
  • `volatile` is definitely not vestigial when dealing with hardware that could change values without the compiler knowing. This is incredibly common in microcontroller programming and is a critical feature to inform compilers which reads/writes cannot be optimized away. – Cameron Tacklind Jul 19 '23 at 23:51
  • @CameronTacklind and all those volatile objects are scalar, or arrays thereof, there's no point writing volatile overloads for classes – Caleth Jul 20 '23 at 07:20