c++language-lawyermove-constructor

`auto x = nonmoveable{};` rejected by MSVC but allowed by GCC and clang


I am trying to move from T t{ ... }; construction to auto t = T{ ... }; in order to make it consistent with function calls like auto p = std::make_unique<T>(...);.

I am however running into issues when T is not move-assignable:

struct nonmoveable {
    nonmoveable(const nonmoveable&) = delete;
    nonmoveable(nonmoveable&&) = delete;
    nonmoveable& operator=(const nonmoveable&) = delete;
    nonmoveable& operator=(nonmoveable&&) = delete;
};

int main() {
    nonmoveable x = {};
    auto y = nonmoveable{};
}

Run on godbolt.

The code above compiles fine on GCC and clang, but fails on MSVC. Changing auto to nonmoveable results in the same error:

(10): error C2280: 'nonmoveable::nonmoveable(nonmoveable &&)': attempting to reference a deleted function (3): note: see declaration of 'nonmoveable::nonmoveable' (3): note: 'nonmoveable::nonmoveable(nonmoveable &&)': function was explicitly deleted

Who is correct according to the standard?

I know that recent revisions introduced a lot of rules regarding copy and move ellisions, but it is not clear to me whether you are allowed to ellide a deleted operation. Pure compiler optimization using the "as if" rule would clearly be forbidden, since the naively equivalent auto y = std::move(x); cannot compile.


Solution

  • Answered in comments by @cpplearner:

    Guaranteed copy/move ellision which allows the code to work even if the copy/move is explicitly or implicitly deleted was added in C++17

    Issue is not about compilers, but by the their default C++ versions. MSVC -std:c++14 and GCC/clang -std=c++14 all fail to compile, while for c++17 they all work, as expected.

    CppReference