What is the correct way to pass a std::vector to be a parameter?

241 Views Asked by At

I want to pass the a vector filled with object based same class. Both std::reference_wrapper and no-reference do not fix it. What's the correct way to solve this?

class MyClass
{
public:
    MyClass(int){};
    virtual void print() const {
        std::cout<<"MyClass"<<std::endl;
    }
};
class MySubClass : public MyClass
{
public:
    MySubClass(int a):MyClass(a){};
    virtual void print() const {
        std::cout<<"MySubClass"<<std::endl;
    }
};
void test(const std::vector<std::reference_wrapper<MyClass>>& v)
{
    for (const auto& c : v) {
        c.get().print();
    }
}
void test(const std::vector<MyClass>& v)
{
    for (const auto& c : v) {
        c.print();
    }
}
int main() 
{
    {
        MySubClass s(2);
        std::vector<MyClass> v;
        v.push_back(s);
        test(v);//print MyClass, but I need MySubClass
    }
    {
        MySubClass s(2);
        std::vector<std::reference_wrapper<MyClass>> v;
        v.push_back(s);
        test(v);//print MySubClass
        test({2});
        test({s});//wrong ambigious
    }
    return 0;
}
1

There are 1 best solutions below

3
On
{
    MySubClass s(2);
    std::vector<MyClass> v;
    v.push_back(s);
    test(v);//print MyClass, but I need MySubClass
}

The problem here is that you're attempting to store MySubClass objects in a vector of MyClass. It is not possible to store the entire MySubClass, instead only the MyClass parent subobject is stored. This conflicts with your desire to treat the stored objects as if they were MySubClass instances.

{
    MySubClass s(2);
    std::vector<std::reference_wrapper<MyClass>> v;
    v.push_back(s);

This solves the previous problem. References can refer to a subclass of their static type. Although, keep in mind that the object is not stored in the vector. The object is stored as a local variable s and only referenced by the vector.

    test(v);//print MySubClass
    test({2});
    test({s});//wrong ambigious

The problem here is that you have two overloads, of which neither accept a MySubClass, but both accept something that can be initialized from an initialization list of MySubClass. Therefore the overload resolution is abiguous. The compiler doesn't know which overload you intended to call.

Either use explicit temporary initialization instead of a plain initializion list.

    test(std::vector<MyClass>{2});
    test(std::vector<std::reference_wrapper<MyClass>>{s});

Or don't use overloads, but uniquely named functions instead.

void test(const std::vector<std::reference_wrapper<MyClass>>& v)
void test2(const std::vector<MyClass>& v)