1

Can you tell me what is wrong in the following example? I am using C++17, where I thought the following should be supported.

class Base {
public:
    virtual ~Base() = default;
};

struct Derived : public Base {
    int m1;
};

int main() {
    /* Results in a compilation error 
     * error C2440: 'initializing': cannot convert from 'initializer list' to 'Derived'
     * message : No constructor could take the source type, or constructor overload resolution was ambiguous */
    Derived d{ {},1 };
    return 0;
}
danielschemmel
  • 10,885
  • 1
  • 36
  • 58
user137589
  • 163
  • 8
  • 4
    `Derived` isn't an aggregate, since it has a base class with virtual members. So it can't be initialized as an aggregate. – Some programmer dude Dec 20 '21 at 07:59
  • Removing the virtual destructor in Base does result in the same compilation error, why so? (And I guess this would be a dangerous solution...) – user137589 Dec 20 '21 at 08:12
  • 1
    Which version of MSVC do you use? Have you tried to explicitly set C++17 mode (`/std:c++17`)? – Some programmer dude Dec 20 '21 at 08:19
  • fwiw, the difference between `struct` and `class` is not relevant for your issue. You'd get the same with `class Derived : public Base { public: int m1; };` See https://stackoverflow.com/questions/54585/when-should-you-use-a-class-vs-a-struct-in-c – 463035818_is_not_an_ai Dec 20 '21 at 08:59
  • @user - Not having a virtual destrutor is dangerous **only** if you delete a Derived through a pointer to Base. As you don't use `new` and `delete`, nothing bad happens. Also, in VS2022 the code compiles fine (without the destructor). – BoP Dec 20 '21 at 10:43
  • FYI: Without the `Base` constructor and the `/std:c++17` added, the code [builds fine](https://godbolt.org/z/veWzTfM4c) with MSVC 19.29. – Some programmer dude Dec 20 '21 at 11:08
  • 1
    Thanks, it works now! I needed to add `set(CMAKE_CXX_STANDARD 17)` and `set(CMAKE_CXX_STANDARD_REQUIRED ON)` to set it to C++ 17 explicitly and remove the virtual destructor in Base. I will use shared_ptrs of Derived and pass them around as shared_ptrs of Base. I guess for this I will need to explicitely implement a constructor to use initialization lists? – user137589 Dec 20 '21 at 11:18
  • 1
    Actually you *don't* need an `std::initializer_list` constructor. The compiler should pick the correct constructor if you declare one. And then you don't need to initialize the base-class in the definition of `d`: `Derived d{1};` (with a suitable `Derived(int)` constructor) will be enough. – Some programmer dude Dec 20 '21 at 11:26
  • Great thanks. `Base` stays as it is, and for `Derived` I will implement a suitable Constructor. I will answer the question and mark it as solved. – user137589 Dec 20 '21 at 11:30

1 Answers1

0

It does not work because Derived is not an aggregate since it has a base class with virtual members.

The code compiles and runs when removing the virtual destructor in Base and using C++17.

If Base requires a virtual destructor, Derived can implement a custom constructor allowing initialization using curly brackets.

class Base {
public:
    virtual ~Base() = default;
};

struct Derived : public Base {
    Derived(int m): m1(m) {}
    int m1;
};

int main() {
    Derived d{ 1 };
    return 0;
}
user137589
  • 163
  • 8