4

Consider the following code:

#include <iostream>
#include <type_traits>

struct type {};

int main(int argc, char* argv[]) {
    std::cout << std::is_convertible_v<volatile int, int> << " ";
    std::cout << std::is_convertible_v<volatile int, volatile int> << " ";
    std::cout << std::is_convertible_v<volatile type, type> << " ";
    std::cout << std::is_convertible_v<volatile type, volatile type> << std::endl;
    return 0;
}

It prints out

1 1 0 0

Why is volatile int convertible to int, but volatile type is not convertible to type? Why is a volatile type not even convertible to volatile type?

Is there a way to make a volatile class copyable?

Note: references to the C++ standard are welcome

Boann
  • 48,794
  • 16
  • 117
  • 146
Vincent
  • 57,703
  • 61
  • 205
  • 388

2 Answers2

4

The implicitly-declared default constructor for type has this signature

type::type(type const&);

The reference cannot bind to a volatile object, since that would discard qualifiers.

[class.copy.ctor]

7 The implicitly-declared copy constructor for a class X will have the form

X::X(const X&)

if each potentially constructed subobject of a class type M (or array thereof) has a copy constructor whose first parameter is of type const M& or const volatile M&. Otherwise, the implicitly-declared copy constructor will have the form

X::X(X&)

Either way, the compiler isn't going to implicitly-declare a constructor that takes a reference to a volatile object.

The fact that the target object in the conversion is volatile too makes no difference. Such a conversion requires a copy constructor capable of binding to a volatile source.

Fundamental types aren't copied by constructors, so this behavior doesn't restrict them.

Is there a way to make a volatile class copyable?

If it's required, you'd need to user-declared copy constructor that accepts by a reference to a const volatile object.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • Nitpick: you *can* have a copy constructor that accepts by reference to **mutable** `volatile`, but *shouldn't* – Caleth Jul 03 '20 at 14:27
1

Such conversion to same type (with qualifiers ignored) is copying / moving.

type has an implicitly generated copy and move constructors which accept a reference to non-volatile qualified object. Such reference cannot be bound to a volatile argument, so conversion from volatile is not allowed.

There are no implicitly generated constructors accepting a reference to volatile qualified object. (Similarly, there are no implicit volatile qualified assignment operators, nor assignment operators with volatile qualified argument).

This is one of the ways C++ is incompatible with valid C where copying volatile structs is allowed.

Is there a way to make a volatile class copyable?

You could technically define constructors that allow it:

struct type {
    type()                       = default;
    type(type          const & ) = default;
    type(type                &&) = default;
    type(type volatile const & ) {}
    type(type volatile       &&) {}
};

Depending on how you expect volatile to behave (access of volatile object is implementation defined), there may not necessarily be a way to implement this constructor in a way that you would expect copying from volatile object to behave if there are several subobjects.

Volatile class objects are generally not very useful, and are best to be avoided in my opinion.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Related - `volatile` deprecated in C++20 in some contexts: https://stackoverflow.com/questions/59223814/why-is-volatile-deprecated-in-c20 – Eljay Jul 03 '20 at 16:38