Search code examples
c++polymorphismcontainersreference-wrapper

std::reference_wrapper and polymorphic containers


I am trying to make a polymorphic vector using std::reference_wrapper for these classes:

struct Int2TypeBase{
    virtual void which(){ std::cout << "Int2TypeBase" << "\n";}
};


template <int v>
struct Int2Type : public Int2TypeBase
{
    enum
    {
        value = v
    };

    void which(){ std::cout << "Int2Type<" << value  << ">""\n";}

    friend bool operator==(const Int2Type& lhs, const Int2Type& rhs){
        return lhs.v == rhs.v;
    }
};

Now I am trying to make use of std::reference_wrapper like this:

int main(){
    using namespace std;

    std::vector<std::reference_wrapper<Int2TypeBase>> v;

    Int2Type<0> i2t_1;
    v.emplace_back(i2t_1);

    auto x = v[0];
    x.get().which();

    std::cout << typeid(x.get()).name() << "\n";

    // std::cout << (x.get() == i2t_1) << "\n";
}

The output is:

Int2Type<0>
8Int2TypeILi0EE

This is what I would expect.

Now however, when I uncomment std::cout << (x.get() == i2t_1) << "\n"; I will get

invalid operands to binary expression ('Int2TypeBase' and 'Int2Type<0>')

This confuses me, as typeid(x.get()).name() returned 8Int2TypeILi0EE rather than F12Int2TypeBasevE which is what I get for typeid(Int2TypeBase()).name();. Furthermore which() also was called for the derived class... so then why does x.get() in x.get() == i2t_1 evaluate to a Int2TypeBase?


Solution

  • At compile time, the compiler can only tell that the type of x.get() is Int2TypeBase, because as declared you can put any Int2TypeBase there. So at compile time, it can't determine that the == operator will work.

    At run time, the objects you put in the collection reference their full type, so typeid returns what you expect and the correct virtual function is called.