c++c++17c++20ctor-initializer

Member initialization while using delegate constructor


The C++ standard does not allow delegate constructors and member initializers in a single mem-initializer-list, yet the following code compiles fine with clang++ and g++.

#include <iostream>
 
class Shape {
public:
        Shape();
};
 
class Circle : public Shape {
public:
        std::string name;
        Circle(std::string name);
};
 
Shape::Shape() {
        std::cout << "Shape constructor" << std::endl;
}
 
Circle::Circle(std::string name) : Shape::Shape(), name(name) { /* <--- Expected an error here! */
        std::cout << "Circle constructor" << std::endl;
}
 
int main() {
        Circle c("my_circle");
        std::cout << c.name << std::endl;
 
        return 0;
}

The relevant quote from the C++ 20 standard is (emphasis mine):

(§11.10.2/6) A mem-initializer-list can delegate to another constructor of the constructor’s class using any class-or-decltype that denotes the constructor’s class itself. If a mem-initializer-id designates the constructor’s class, it shall be the only mem-initializer; the constructor is a delegating constructor, and the constructor selected by the mem-initializer is the target constructor.[...]

Did I misread the C++ standard? Do clang++ and g++ deviate from the standard here?


Solution

  • You are not using a delegating constructor.

    A delegating constructor calls another constructor in the same class.

    For example, in:

    struct Foo
    {
        Foo(int) : Foo("delegate") {} // #1
        Foo(std::string) {} // #2
    };
    

    #1 and #2 are both constructors for Foo, and constructor #1 delegates to constructor #2.

    In your case, you have a class that is derived from another class, and in:

    Circle::Circle(std::string name) : Shape::Shape(), name(name)
    

    You are initializing the base Shape portion of the Circle object, by calling Shapes default constructor. You then move on after that to finish initializing the rest of the members of the Circle class. This is not a delegating constructor.