Consider following code:
struct S
{
S() = default;
S(S const&) = delete;
// S(S&&) = delete; // <--- uncomment for a mind-blowing effect:
// MSVC starts compiling EVERY case O_O
};
S foo() { return {}; }
struct X : S
{
// X() : S(foo()) {} // <----- all compilers fail here
};
struct Y
{
S s;
Y() : s(foo()) {} // <----- only MSVC fails here
};
struct Z
{
S s = {}; // ... and yet this is fine with every compiler
Z() {}
};
//S s1(foo()); // <-- only MSVC fails here
//S s2 = foo(); // <-- only MSVC fails here
Questions:
It looks like there is no way to initialize non-copyable base class with a prvalue -- is this correct? Looks like a deficiency in standard (or all compilers I tried are non-compliant)
MSVC can't initialize member variable -- does it mean it is non-compliant? Is there a way to workaround this?
why adding S(S&&) = delete;
causes MSVC to compile every case?
Yes. This code: class MyClass { public: int a = 1; int b = 2; };
We can put static members (Functions or Variables) in C++ classes. For the static variables, we have to initialize them after defining the class. To initialize we have to use the class name then scope resolution operator, then the variable name. Now we can assign some value.
In C++, class variables are initialized in the same order as they appear in the class declaration. Consider the below code. The program prints correct value of x, but some garbage value for y, because y is initialized before x as it appears before in the class declaration.
The constructors should be used to initialize member variables of the class because member variables cannot be declared or defined in a single statement. Therefore, constructors are used in initializing data members of a class when an object is created.
So, I think I found the relevant parts of the standard and I think the compilers are in error regarding to X
. (All links are to a standard draft so very maybe it was different in C++17, I will check that later. But gcc10 and clang10 also fail with -std=c++20
, so that is not that important).
Regarding the initialization of base classes (emphasis mine): class.base.init/7
The expression-list or braced-init-list in a mem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of [dcl.init] for direct-initialization.
I think this tells us, that X() : S(foo()) {}
should not be different from S s = foo()
, but let's look at dcl.init/17.6.1
If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object. [Example:
T x = T(T(T()));
calls theT
default constructor to initializex
. — end example]
This implies to me, that X() : S(foo()) {}
should call the default constructor. I also tested (to be completely in line with the example) X() : S(S()) {}
and this also fails on clang and g++. So it seems to me that the compilers have a defect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With