Search code examples
c++gccvisual-c++polymorphismc++20

Are destructors of library types well defined?


For example the iterator type - here I need to have a polymorphic iterator of different types depending on the usage. So I create a union with user defined constructor and destructor:

I'm specifically questioning the destructors names (eg. ~iterator()).

#include <list>
#include <string>

struct val_origin {
    union {
        std::list<std::list<std::string>>::iterator iterenum;
        std::list<std::list<std::list<struct var>>>::iterator iterunorstr;
        std::list<struct var>::reverse_iterator vartypedef;
    };

    enum ORIG_ENUM {
        ORIG_ENUM_TYPE,
        ORIG_STRUC_TYPE,
        ORIG_TYPEDEF,
        ORIG_PLAIN
    } orig;

    val_origin(ORIG_ENUM orig) {
        switch (orig) if (0)
        case ORIG_ENUM_TYPE:
            new (&iterenum)decltype(iterenum) {};
        else if (0)
        case ORIG_STRUC_TYPE:
            new (&iterunorstr)decltype(iterunorstr) {};
        else if (0)
        case ORIG_TYPEDEF:
            new (&vartypedef)decltype(vartypedef) {};
    }

    val_origin& operator=(const val_origin& val_origin_in) {
        this->~val_origin();

        new (this)val_origin{ val_origin_in };
    }

    val_origin(const val_origin& val_origin) {
        switch (orig) if (0)
        case ORIG_ENUM_TYPE:
            iterenum = val_origin.iterenum;
        else if (0)
        case ORIG_STRUC_TYPE:
            iterunorstr = val_origin.iterunorstr;
        else if (0)
        case ORIG_TYPEDEF:
            vartypedef = val_origin.vartypedef;
    }

    ~val_origin() {
        switch (orig) if (0)
        case ORIG_ENUM_TYPE:
            iterenum.decltype(iterenum)::~iterator();
        else if (0)
        case ORIG_STRUC_TYPE:
            iterunorstr.decltype(iterunorstr)::~iterator();
        else if (0)
        case ORIG_TYPEDEF:
            vartypedef.decltype(vartypedef)::~reverse_iterator();
    }
};

Now my issue is that the above code compiles fine on gcc. But when I switch to clang or MSVC it fails.

My question is if this a standard code or not (would appreciate citation from the standard, I wasn't able to find the relevant info) and also if not what is my other option for implementing this.

I'm trying to have a dynamic (run-time) polymorphic iterator (same object but different type of iterators which will be used by different parts of the code appropriately).

The code fails on MSVC because the destructor name is not known.


Solution

  • Name lookup for destructors is very subtle to support things like typedef-names for non-class types. There’s no guarantee, though, that iterator is available here since the iterator need not be a class type named iterator (or reverse_iterator) so as to provide that as an injected-class-name and since there’s no declaration for unqualified lookup to find.

    Moreover, after recent clarifications the rule is that decltype(…)::~… is just invalid ([expr.prim.id.qual]/4). Of course, there’s very little reason to qualify destructor “names” anyway: you can just write

    iterenum.~decltype(iterenum)();
    

    and so on.