std::reference_wrapper and polymorphic containers

2019-09-07 07:46发布

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?

2条回答
Summer. ? 凉城
2楼-- · 2019-09-07 08:27

Your comparison operator is only defined for derived classes, but the reference wrapper produces (static) type Int2Base, so overload resolution does not even find your comparison operator!

What you probably need is a comparison operator of the form

bool operator==(const Int2TypeBase& lhs, const Int2TypeBase& rhs)

but then you also need to have some sort of polymorphic dispatch to perform the actual comparison (presumably assuming that the dynamic types match).

查看更多
放我归山
3楼-- · 2019-09-07 08:32

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.

查看更多
登录 后发表回答