0

No problem to assign one struct to another by value when they both have the same type...

#include <iostream>

using namespace std;

struct t {
    int y;
};

int main()
{
    
    t a={1};
    t b;
    
    b=a;
    
    cout<< a.y << '\n';
    cout<< b.y << '\n';

    return 0;
}

..which prints two 1s as expected. But if I modify the source struct to be volatile, like this...

#include <iostream>

using namespace std;

struct t
{
  int y;
};

int
main ()
{

  volatile t a = { 1 };

  t b = a;
  
  cout << a.y << '\n';
  cout << b.y << '\n';

  return 0;
}

(https://onlinegdb.com/McFd3jJ_r)

...then I get compiler errors like...

.main.cpp: In function ‘int main()’:
main.cpp:24:9: error: no matching function for call to ‘t(volatile t&)’
   24 |   t b = a;
      |         ^
main.cpp:13:8: note: candidate: ‘constexpr t::t(const t&)’ (near match)
   13 | struct t
      |        ^
main.cpp:13:8: note:   conversion of argument 1 would be ill-formed:
main.cpp:24:9: error: binding reference of type ‘const t&’ to ‘volatile t’ discards qualifiers
   24 |   t b = a;
      |         ^
main.cpp:13:8: note: candidate: ‘constexpr t::t(t&&)’ (near match)
   13 | struct t
      |        ^
main.cpp:13:8: note:   conversion of argument 1 would be ill-formed:
main.cpp:24:9: error: cannot bind rvalue reference of type ‘t&&’ to lvalue of type ‘volatile t’
   24 |   t b = a;
      |         ^

Why am I not able to read from a volatile struct to assign it to another struct?

I can manually go through and assign each of the members from the volatile source to the destination and this works fine, but this is not good for abstraction because now the code doing the assignment needs to know all of the members.

What is the correct way to do struct assignments by value when the source struct are volatile?

bigjosh
  • 1,273
  • 13
  • 19
  • *"no matching function for call to ‘t(volatile t&)"* So you could add such a member to your struct, thereby defining what it **really** means to copy from a volatile struct. For example, if the struct had two members, should the code read both at once (how?), or transform one volatile read into two separate reads!? – BoP Mar 19 '23 at 11:24
  • In my real use case, the `volatile` object is of a templated type, so I can not go inside to the member functions. But I really do not think I should need to - for example I can use a `volatile long` as an r-value on a 16 machine and I do not need to copy the individual words, so there is nothing in volatile semantics about the order in which *internal* data is copied as long as all is copied inside the memory barrier. – bigjosh Mar 20 '23 at 02:52
  • It looks like the correct answer is "you cannot do this because of the way the standard choose to implement the copy constructor".... https://stackoverflow.com/a/17218983/3152071 – bigjosh Mar 20 '23 at 02:57
  • Of course the choice wasn't random. The rules for `volatile` is that each read and write have to be performed exactly as coded. I have seen cases where reading from a memory mapped status register triggered an action on an expansion board. Splitting a single read into two reads would trigger two actions instead of one. Bad if the action is write to the hard disk. Are you perhaps looking for [thread synchronization](https://en.cppreference.com/w/cpp/thread) instead of external hardware synchronization? – BoP Mar 20 '23 at 09:10

0 Answers0