0

I have a class A and its subclass B and a method that takes std::vector<A>. And I cannot make it work by passing std::vector<B>.

I though that if subclass B can be casted to A, I should be able to pass vector of Bs to method that takes vector of As. How can I do that properly?

#include <iostream>
#include <vector>

class A {

    public:

        A() {}
};

class B: public A {

    public: 

        B(): A() {}
};

void method(std::vector<A> a) {}

int main() {
    std::vector<B> b;
    method(b);

    return 0;
}

When compiled:

g++ ex-cast-tag.cpp -std=c++11

ex-cast-tag.cpp:22:5: error: no matching function for call to 'method'
    method(b);
    ^~~~~~
ex-cast-tag.cpp:18:6: note: candidate function not viable: no known conversion from 'vector<B>' to 'vector<A>'
  for 1st argument
void method(std::vector<A> a) {}
     ^
1 error generated.

Thanks in advance!

Tomasz Szulc
  • 4,217
  • 4
  • 43
  • 79
  • 1
    Use pointers instead of objects. – Ripi2 Jul 19 '18 at 19:33
  • 3
    Template specializations with different arguments are not related, even if the arguments are related. Try making `method()` a template function. –  Jul 19 '18 at 19:33
  • 1
    Related: https://stackoverflow.com/questions/51428853/cast-stdlistx-to-stdlisty – πάντα ῥεῖ Jul 19 '18 at 19:33
  • 1
    @Ripi2 it does not change anything. Result is the same. Compiler says `no know conversion from vector to vector`. – Tomasz Szulc Jul 19 '18 at 19:34
  • @Ripi2 Both the parameter type and the value passed in must be `vector`. – Code-Apprentice Jul 19 '18 at 19:37
  • 1
    "Use pointers" in the sense that you can have a vector of base class pointers, and insert derived class pointers in there. You will not need `vector`, only `vector`. –  Jul 19 '18 at 19:38
  • 1
    closing this a dupe is rather unfortunate, as the alleged dupe is pre 2011, and answers using `enable_if`, for example, are not allowed, but are useful here. – Walter Jul 19 '18 at 20:31

2 Answers2

3

One solution is to use a template. For example

template<typename C>
std::enable_if_t<std::is_base_of<A,C>::value>
method(std::vector<C> const&a) 
{
    // assume that a[i] is an A (derived or actually the same)

}

Here, I have used SFINAE to ensure that C is actually A or derived from A. But you can also use static_assert instead. In this case you get nicer error messages, but the overloading behaviour of method() is different (i.e. when this template is considered).

Walter
  • 44,150
  • 20
  • 113
  • 196
1

If B is a subclass of A, it does not follow that std::vector<B> is a subclass of std::vector<A>. In order to use inheritance correctly here, you need to change the function to accept a parameter of type std::vector<A*> then pass it a std::vector<A*> whose pointers all point to instances of type B. Alternatively, you can make the function into a template function.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268