Search code examples
c++inheritancestructaggregate-initialization

Inherited struct members inaccessible during aggregate initialization


#include <vector>
#include <string>

struct BasePluginInfo
{
    bool bHasGui, bIsSynth;
    char cType;
    std::string sCategory, sSdkVersion, sVendor, sVersion;
};

struct PluginClassInfo
{
    std::string sName, sUid;
    std::vector<std::string> vsParamNames;
};

struct ShellPluginInfo : BasePluginInfo
{
    std::vector<PluginClassInfo> vciClasses;
};

When I do

int main() {
    ShellPluginInfo
    {
        .bHasGui = true
    };
}

The compiler complains that ShellPluginInfo has no field 'bHasGui'.

However this works:

int main() {
    ShellPluginInfo info;
    info.bHasGui = true;
}

Solution

  • When aggregate initializing something with base classes, the base class acts like a member of the class, similar to if you had:

    struct ShellPluginInfo {
        BasePluginInfo __base_class_subobject;
        std::vector<PluginClassInfo> vciClasses;
    };
    

    As such, the first clause in the initializer list will try to initialize it, and you have to write:

    ShellPluginInfo{  // This initializer list initializes a ShellPluginInfo
        { .bHasGui = true; }  // This initializer list initializes a BasePluginInfo
    }
    

    However, since this is not a designated initializer, you cannot use designated initializers for the rest of the members of the derived class. For example:

    ShellPluginInfo{
        {  // (note: doesn't have a designator)
            .bHasGui = true,
            .cType = 'a'  // OK
        },
        .vciClasses = {}  // ERROR: Can't mix designated and non-designated initializers
    
    }
    

    This proposal attempts to remedy that: https://wg21.link/p2287r1, making your original attempt valid. It has not been accepted yet though, but you may see it in C++23.