Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to initialize member variable (or base class) of a non-copyable type?

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?

like image 397
C.M. Avatar asked Jul 15 '20 18:07

C.M.


People also ask

Can we initialize data members in a class without constructor?

Yes. This code: class MyClass { public: int a = 1; int b = 2; };

Can we initialize member variable in class in C++?

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.

Can we initialize data members in a class?

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.

Can we initialize a class member variable as soon as the same is defined?

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.


1 Answers

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 the T default constructor to initialize x. — 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.

like image 50
n314159 Avatar answered Nov 15 '22 20:11

n314159