Thanks to helpful comments to my question, I try to answer the question myself with the best of my knowledge. Please comment if you spot mistakes.
Whether the code compiles or not has to do with the C++ version used.
The given code
- compiles with C++17 (use gcc 11 or gcc 10 with option
-std=c++17
) and
- does not compile with C++14 (use gcc 10 or gcc 11 with option
-std=c++14
).
The difference between both C++ versions with regard to this issue is based on "mandatory elision of copy/move operations" starting with C++17, see here.
Using C++14, appropriate constructors need to be defined in order to construct s_t io1
.
To see this more easily, in the linked example switch to "x64-64 clang 13.0.0)". This compiler provides diagnostic messages that are easier to comprehend in my opinion. "clang" compiles the code when given the option -std=c++17
. Otherwise, it emits error messages:
error: no matching constructor for initialization of 's_t' (aka 'volatile s')
It also lists several implicitly defined constructors that were rejected as "not viable".
In other words, we need to provide the proper constructor manually (aka. user-defined constructor).
First, we need to take care of the initialization of struct s m = {0};
because as soon as we add any user-define constructors, there won't be an implicitly defined constructor any more. See default constructor. Further, aggregate initialization does not apply any more as soon as there are user-defined constructors added to the struct.
This will do s(int i) {}
for compiling (let's omit initialization or other code from constructors).
Second, we will need to provide a constructor for argument type s_t
.
If I declare a constructor s(volatile struct s l) {}
"clang" complains with
error: copy constructor must pass its first argument by reference
s(volatile struct s l) { }
If I declare a copy constructor s(volatile struct s & l) { }
"clang" complains with
error: no matching constructor for initialization of 's_t' (aka 'volatile s')
However, if I declare a move constructor s(volatile struct s && l) { }
the code compiles (with clang and gcc, C++14 and C++17).
This is the resulting code to try for yourself.