Why the move constructor is not explicit anymore in C++17

In the latest update of C++ to version C++17 there was some things which were changed, for example, the constructor of std::pair<int, const std::unique_ptr<int>> from an rvalue of type std::pair<int, std::unique_ptr<int>> is explicit in C++14, and implicit and C++17.

Note that this behavior was only seen in  libstdc++ and libc++ libraries. In MSVC’s library, the constructor is always implicit.

This article will discuss why the move constructor was explicit in C++14 and why it was changed in C++17.

Detailed reason to understand why the move constructor is not explicit anymore in the latest version of C++ that is C++17 is given below:

Why the move constructor is not explicit anymore in C++17?

For a short explanation, you should know that the return statement from the move constructor copy-initializes the A return value from the operand and before C++17, but in C++ 17 version mandatory copy elision applies and the copy-initialization does not contain the direct-initialization via the move constructor anymore.

To understand why the move constructor is not explicit anymore in C++17, you need to know that the relevant constructors have not been explicit before C++17 either.

For example, the GCC and Clang in before the C++17 version was launched, are actually considering std::is_convertible<B, A>::value false because A‘s ‘move’ constructor is implicitly deleted.

The move constructor is implicitly deleted, because a const std::unique_ptr cannot be moved or copied in the code.

The move constructor is required to fulfill the following command std::is_convertible<B, A>::value before C++17, because it tests whether a function of the form, given below, would be well-formed:

A test() {
    return std::declval<B>();
}

The return statement copy-initializes the A return value from the operand and before C++17, copy-initialization always involved a conversion to a temporary of the target type if necessary, then followed by direct-initialization of the target from the temporary.

That direct-initialization would use the move constructor of A. The move can be elided by the compiler, but the move constructor must still be usable.

Since the C++17 compulsory copy elision applies and even conceptually, the copy-initialization does not contain the direct-initialization via the move constructor anymore.

This is the reason why the move constructor is not explicit anymore in the latest version of C++ that is C++17

Conclusion

To understand ‘Why the move constructor is not explicit anymore in C++17’ a short explanation would be,you should know that the return statement from the move constructor copy-initializes the A return value from the operand and before C++17.

But now in C++17 mandatory copy elision applies and the copy-initialization does not contain the direct-initialization via the move constructor anymore.