Search code examples
c++c++17type-deductionstd-variant

Implementation of a polymorphic [] operator for accessing a std::variant


Suppose I have a struct MyMap, which is a wrapper for std::map where value type is std::variant<A, B> but A and B behave completely different (they have different member functions and fields, and share no common functionality).

For example:

#include <map>
#include <variant>
#include <string>

struct A {
   std::string val;
};

struct B {
   int val;
};

struct MyMap {
   std::map<int, std::variant<A, B>> internalMap;
};

I want to implement an operator[] overload for MyMap such that the type of the accesed element is the actual type A or B.

To clarify further, i DO NOT want this: std::variant<A, B> operator[](int key) { return internalMap[key]; } , but I want something like:

// If I have:

MyMap m;
m.internalMap[1] = A{};
m.internalMap[2] = B{};

// I want the type of internalMap[1] to be A, and type of internalMap[2] to be B:
A a = m.internalMap[1];
B b = m.internalMap[2];

I want to be able to call methods specific to type A or type B after accessing them with this operator[] overload.

Should this type deduction happen at runtime or at compile time (and how)?


Solution

  • struct AorB : public std::variant<A, B> {
        using std::variant<A, B>::variant;
    
        operator A&() {return std::get<A>(*this);}
        operator const A&() const {return std::get<A>(*this);}
        operator B&() {return std::get<B>(*this);}
        operator const B&() const {return std::get<B>(*this);}
    };
    

    And then you store this as the value of the map. Then, you can pass this to methods expecting an A or a B, and it works, as long as it's unambiguous.

    A a = m.internalMap[1]; //no problem!
    B b = m.internalMap[2];
    

    Proof of execution