Во-первых, заголовок, возможно, не отражает текущий вопрос, поэтому, пожалуйста, не стесняйтесь менять.Предполагая, что у меня есть следующие классы:
#include <iostream>
#include <vector>
template <typename K, class V>
class A {
public:
K x;
V y;
A(K x, V y):x(x), y(y) {}
void print(A<K, V>& z) {
std::cout << x + z.x << "-" << y + z.y << std::endl;
}
void print(std::vector<A<K,V>> z) {
for(auto& i:z) {
print(i);
}
}
};
class B:public A<int, std::string> {
public:
B():A(0, "zero") {}
B(int x, std::string y):A(x, y) {}
};
void test() {
B b1(1, "one");
B b2(2, "two");
B b3(3, "three");
B b4(4, "four");
B b5(5, "five");
b5.print(b1);
//
std::vector<B> c;
c.push_back(b1);
c.push_back(b2);
c.push_back(b3);
c.push_back(b4);
b5.print(c);
}
Я получаю следующую ошибку в последней последней строке (b5.print(c)
);
test_class.cpp:40:6: error: no matching member function for call to 'print'
b5.print(c);
~~~^~~~~
test_class.cpp:10:8: note: candidate function not viable: no known conversion from 'std::vector<B>' to 'A<int, std::__1::basic_string<char> > &' for 1st argument
void print(A<K, V>& z) {
^
test_class.cpp:13:8: note: candidate function not viable: no known conversion from 'vector<B>' to 'vector<A<int, std::__1::basic_string<char> >>' for 1st argument
void print(std::vector<A<K,V>> z) {
^
1 error generated.
Я в основном ожидаю неявное преобразование из vector<B>
до std::vector<A<int,std::string>>
но это не так.Поэтому я нашел два решения этой проблемы:
- Определить
typedef std::vector<A<int,std::string>> MyWeirdVector;
в классе A и использовать se B::MyWeirdVector c;
вместо std::vector<B> c;
. - Определить каждую функцию печатикак
template <typename U>
в классе A и принять имя типа U в качестве аргумента.
У обоих решений есть свой недостаток.Во-первых, я должен создать экземпляр c как B :: MyWeirdVector, а во-вторых, я не чувствую безопасности типов.Второе решение работает, даже если я не определяю тип в <>
.
Итак, есть ли элегантное решение этой проблемы, например, неявное преобразование типов из std::vector<B>
в std::vector<A<int,std::string>>
?
- РЕДАКТИРОВАТЬ -
Благодаря @ max66, @Caleth и другим сотрудникам.Я просто хочу поделиться полным рабочим примером.Пожалуйста, обратите внимание, что void
до print
не существует для ответа @ max66, если вы не хотите сходить с ума.(1. Все аргументы функции печати: const
, 2. Объедините ответы от @ max66 и @Caleth.)
#include <iostream>
#include <vector>
#include <type_traits>
template <typename K, class V>
class A {
public:
K x;
V y;
A(K x, V y):x(x), y(y) {}
void print(const A<K, V>& z) {
std::cout << x + z.x << "-" << y + z.y << std::endl;
}
// for C++11, thanks to @Caleth
// template <typename Container, typename = typename std::enable_if<!std::is_base_of< A<K,V>, typename std::remove_reference<Container>::type >::value>::type>
// void print(Container&& z) {
// for(auto& i:z) {
// print(i);
// }
// }
// thanks to @max66
template <typename T>
typename std::enable_if<std::is_base_of<A<K, V>, T>::value>::type
print(std::vector<T> const & z) {
for(auto const & i:z) print(i);
}
};
class B:public A<int, std::string> {
public:
B():A(0, "zero") {}
B(int x, std::string y):A(x, y) {}
};
void test() {
B b1(1, "one");
B b2(2, "two");
B b3(3, "three");
B b4(4, "four");
B b5(5, "five");
b5.print(b1);
//
std::vector<B> c;
c.push_back(b1);
c.push_back(b2);
c.push_back(b3);
c.push_back(b4);
b5.print(c);
}