Skip to content

[class.copy.assign]/7 and "corresponding" assignment operator in a union-like class #4536

Closed
@brevzin

Description

@brevzin

The title section currently reads:

A defaulted copy/move assignment operator for class X is defined as deleted if X has:

  • a variant member with a non-trivial corresponding assignment operator and X is a union-like class, or
  • a non-static data member of const non-class type (or array thereof), or
  • a non-static data member of reference type, or
  • a direct non-static data member of class type M (or array thereof) or a direct base class M that cannot be copied/moved because overload resolution ([over.match]), as applied to find M's corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator.

What is the "corresponding assignment operator"? Consider the following example (from @foonathan):

#include <type_traits>

//=== the setup ===//
// This class is weird, but Microsoft's std::pair works the same.
struct foo
{
    // foo has a trivial default constructor, copy constructor, move constructor and destructor.
    foo() = default;
    foo(const foo&) = default;
    foo(foo&&)      = default;
    ~foo() = default;

    // For the compiler, this is a copy assignment operator.
    // http://eel.is/c++draft/class.copy.assign#1 
    foo& operator=(const volatile foo&) = delete;

    // For the compiler, this is not a copy assignment operator.
    // This is just a weird operator overload.
    template <int Dummy = 0>
    foo& operator=(const foo&) // non-trivial
    {
        return *this;
    }
    // For the compiler, this is not a move assignment operator.
    // This is just a weird operator overload.
    template <int Dummy = 0>
    foo& operator=(foo&&) // non-trivial
    {
        return *this;
    }
};

template <typename T>
struct my_optional
{
    union
    {
        char empty;
        T value;
    };
};

static_assert(!std::is_copy_assignable_v<my_optional<foo>>);

All compilers agree that my_optional<foo> is not copy assignable, because copy assignment would be non-trivial. But the variant member T value here does have a trivial copy assignment operator (the "corresponding assignment operator") -- but it's not the one that would be used when performing copy assignment.

We need to do the same "overload resolution ([over.match]), as applied to find M's corresponding assignment operator" thing from the 4th bullet point to also handle the 1st bullet point cases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    cwgIssue must be reviewed by CWG.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions