候选函数不可行:没有从 std::vector<derived> 到 std::vector <base>的已知转换
candidate function not viable: no known conversion from std::vector<derived> to std::vector<base>
首先,标题可能无法反映当前的问题,因此请随时更改。假设我有以下课程;
#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;
. - 将每个打印函数定义为 A 类中的
template <typename U>
,并接受类型名 U 作为参数。
这两种解决方案都有其自身的缺点。首先,我必须将c实例化为B::MyWeirdVector,其次,我没有(感觉(类型安全。即使我不在<>
中定义类型,第二种解决方案也有效。
那么,有没有一个优雅的解决方案来解决这个问题,比如让隐式类型从std::vector<B>
转换为std::vector<A<int,std::string>>
?
--编辑--
感谢@max66和@Caleth以及其他研究员。我只想分享完整的工作示例。请注意,如果您不想发疯,print
之前没有void
@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);
}
怎么样
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>
的内容(泛型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); }
将每个打印函数定义为模板
<typename U>
取而代之的是,请仅定义使用类型名引发错误的打印函数。
由于这两种类型完全不同,因此隐式转换不是一种选择,但我的建议是。
对于最大的通用性:
template<typename Container, typename = std::enable_if_t<!std::is_base_of_v<A<K, V>, std::remove_reference_t<Container>>>>
void print(Container&& z) {
for(auto & i : z) {
print(i);
}
}
这是类型安全的。如果您尝试传递不是(可能嵌套的(A<K, V>
容器的内容,则模板实例化将失败。
- 尝试使用 std::vector<std::thread时出现静态断言失败错误>
- 字符串化递归的"std::vector<std::vector<...>>"而不使用部分模板函数专用化
- 连接和压缩标准::vector<std::字符串的最佳方法>
- C++从 std::vector<std::function<中删除 std::function>>
- 如何在构造函数初始值设定项列表中使用 n 个元素初始化 std::vector<std::time_t>
- 如何使用 CUDA 将 std::vector<std::string> 复制到 GPU 设备
- 编译错误 std::vector<std::shared_ptr<T>>迭代器和擦除方法
- 将 std::vector<std::unique_ptr<T>> 移动到 std::vector<std::shared_ptr<T>>
- 如何从 boost::container::vector<std::string>::iterator 访问索引和对象?
- 使用 std::vector<std::future<int>> 和 std::async 启动几个线程时中止
- 为什么转置这个 std::vector<std::vector<std::string> > 这么慢?
- 是否有可能在没有复制的情况下传递 std::vector<int> 作为参数来获得 std::vector<std::array<int, 3>>?
- 在 boost::<double>asio::buffer 中使用像 std::vector<std::complex> 这样的参数
- 如何从 std::initializer_list<char const* 构建 std::vector<std::string>>
- 如何检查 std::vector<std::string> 的元素是否以某个子字符串开头?
- 在 std::vector<std::vector 中重新存储内部向量<TYPE>>
- 将 std::vector<std::string> 转换为 const char* const*
- 不能将结构push_back() 转换为 std::vector<std::shared_ptr<theStruct>> theVector
- SWIG:传递一个 std::vector< std::vector <double> >指向 python 的指针
- 将 std::vector<std::p air<const K, V>*> 转换为 std::vector<std::p air<const K, V>&g