I have an issue with the default move constructor in Visual Studio 2022 (/std:c++latest) in a constexpr context. I do not see the issue in Visual Studio 2019. I have two questions:
- Is it my code or Visual Studio 2022 that is incorrect? If my code is incorrect then why?
- Are similar issues are seen in gcc or clang? (I do currently have access to those compilers.)
Problem statement
In the code below, I have two true/false switches:
DEFAULT_MOVE and CONSTEXPR, therefore giving me four possible programs.
DEFAULT_MOVEcontrols whether the default move constuctor or a home-brew move constructor is used.CONSTEXPRcontrols whether an instance ofContaineris created at compile-time or run-time.
The code does not compile when both DEFAULT_MOVE and CONSTEXPR are both true, yielding the message:
error C3615: constexpr function 'Containerstd::u8string_view,3::Container' cannot result in a constant expression
However, under any other of the three switch combinations the code compiles successfully.
I would have expected the code to compile in all four cases.
#include <array>
#include <cassert>
#include <string_view>
//switches
#define DEFAULT_MOVE true
#define CONSTEXPR true
template<typename T, size_t N>
struct Container{
std::array<T, N> x;
template<typename... Args>
constexpr explicit Container(Args&&...args) : x{std::forward<Args>(args)...} {}
#if DEFAULT_MOVE
//default move ctor
constexpr Container(Container&&) noexcept = default;
#else
//home-brew move ctor
constexpr Container(Container&& other) noexcept : x{} {
for (size_t n{0} ; T& e : other.x)
x[n++] = std::move(e);
}
#endif
constexpr Container(const Container&) = delete;
constexpr Container& operator=(Container&&) = delete;
constexpr Container& operator=(const Container&) = delete;
constexpr ~Container() = default;
};
using X = Container<std::u8string_view, 3>;
using Y = Container<X, 2>;
int main() {
#if CONSTEXPR
// constexpr creation of a Y object
constexpr Y a{X{u8"a",u8"b"}, X{u8"a"}};
static_assert(a.x[0].x[1] == u8"b");
#else
// runtime creation of a Y object
const Y a{X{u8"a",u8"b"}, X{u8"a"}};
assert(a.x[0].x[1] == u8"b");
#endif
}