首先,标题可能无法反映当前问题,因此请随时进行更改。假设我有以下课程;
#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类中定义,并使用seB::MyWeirdVector c;
代替std::vector<B> c;
。template <typename U>
在A类中定义每个打印函数,并接受类型名U作为参数。两种解决方案都有其自身的缺点。首先,我必须将C实例化为B :: MyWeirdVector,其次,我(感觉)没有类型安全性。即使我未在中定义type,第二个解决方案也可以工作<>
。
那么,是否有解决此问题的优雅方法,例如允许将隐式类型转换从转换std::vector<B>
为std::vector<A<int,std::string>>
?
-编辑-
感谢@ max66和@Caleth等人。我只想分享完整的工作示例。请注意,如果您不想发疯,@ max66的答案是没有void
以前print
的。(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);
}
关于什么
template <typename T>
void print(std::vector<T> const & z) {
for(auto const & i:z) {
print(i);
}
}
代替
void print(std::vector<A<K,V>> z) {
for(auto& i:z) {
print(i);
}
}
?
我的意思是:您不能进行从std::vector<B>
到的隐式转换,std::vector<A<K, T>>
但是您可以管理泛型std::vector<T>
(generic T
)的内容并获得(以防万一)从T
元素到的隐式转换A<K, T>
(如果T
是派生类型)。
如果需要,您可以添加std::enable_if
仅当T
从派生时启用模板打印功能A<K, T>
。
-编辑-
OP问
如何使用
std::enable_if
启用模板打印功能以仅对从A派生的对象进行操作?
有很多方法。举例来说,请参见Caleth的答案以及其他模板类型,并std::enable_if
激活它。
但我更喜欢由激活的返回值std::enable_if
。
表示为(警告:未经测试的代码)
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); }
如果您可以使用C ++ 14,则可以进行一些简化(使用std::enable_if_t<>
代替typename std::enable_if<>::type
)
template <typename T>
std::enable_if_t<std::is_base_of<A<K, V>, T>::value>
print(std::vector<T> const & z)
{ for(auto const & i:z) print(i); }
并多使用C ++ 17(std::is_base_of_v<>
而不是`std :: is_base_of <> :: value)
template <typename T>
std::enable_if_t<std::is_base_of_v<A<K, V>, T>>
print(std::vector<T> const & z)
{ for(auto const & i:z) print(i); }
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句